How to use a common target object to handle actions/outlets of multiple views?

前端 未结 2 1925
孤独总比滥情好
孤独总比滥情好 2021-01-03 14:08

I\'m beginning to try and use IB where previously I used code. I have created nibs for iPad/iPhone Portrait/Landscape so I have four possible views. All have files owner set

2条回答
  •  走了就别回头了
    2021-01-03 14:27

    Adam, it sounds like you want a proxy (aka external) object.

    Your Problem

    NSBundle and UINib return auto-released arrays when instantiating object graphs from NIBs. Any object you don't specifically retain will be released when the array is released at the end of the event loop. Obviously objects inside the nib that reference each other will be retained as long as their owner is retained.

    So you 2nd instance of your action target object is being released because you're not hanging on to it.

    What you really want is just a single instance of your target object that both NIBs can reference. So you can't have your NIB instantiate an instance of that object. But your NIB needs to be able to make reference to that object instance!

    Oh dear, what to do?!

    Solution: Proxy/External Objects

    Basically an external object is a proxy you place in a NIB. You then feed in the actual instance that when you instantiate the NIB's object graph. The NIB loader replaces the proxy in the NIB with your externally provided instance and configures any targets or outlets you've assigned to the proxy in Interface Builder.

    How To Do It

    1. In Interface Builder drag in an "External Object" rather than NSObject instance. It will appear in the upper section along with File's Owner in Xcode 4.x.
    2. Select it and in the "Identity Inspector" set it's class to the appropriate type.
    3. In the "Attributes Inspector" set the Identifier string to "TargetObject" (or whatever string you want to use in the code below).
    4. Profit!

    The Code

    id owner = self; // or whatever
    id targetObject = self.targetObject; // or whatever...
    
    // Construct a dictionary of objects with strings identifying them.  
    // These strings should match the Identifiers you specified in IB's 
    // Attribute Inspector.
    NSDictionary *externalObjects = [NSDictionary dictionaryWithObjectsAndKeys:
                                        targetObject, @"TargetObject",
                                        nil];
    
    // Load the NIBs ready for instantiation.
    UINib *portraitViewNib = [UINib nibWithNibName:@"Weekview_iPad_Portrait" bundle:nil];
    UINib *landscapeViewNib = [UINib nibWithNibName:@"Weekview_iPad_Landscape" bundle:nil];
    
    // Set up the NIB options pointing to your external objects dictionary.
    NSDictionary *nibOptions = [NSDictionary dictionaryWithObjectsAndKeys:
                                   externalObjects, UINibExternalObjects, 
                                   nil];
    
    // Instantiate the objects in the nib passing in the owner 
    // (coincidentally also a proxy in the NIB) and your options dictionary.
    NSArray *portraitViewArray =  [portraitViewNib instantiateWithOwner:owner
                                                                options:nibOptions];
    NSArray *landscapeViewArray = [landscapeViewNib instantiateWithOwner:owner
                                                                 options:nibOptions];
    
    self.view = [(UIInterfaceOrientationIsPortrait(interfaceOrientation)) ? portraitViewArray : landscapeViewArray) objectAtIndex:0];
    

    Notes

    You're using NSBundle to load NIBs. You should be using UINib. It is much faster at reading the NIB files. Also, it separates the NIB loading from the object instantiation. Which means you can load the NIB in your init, awakeFromNib, or viewDidLoad and not instantiate the contents of the NIB. Then at the last possible moment when you need the actual objects in the NIB to you can call instantiateWithOwner.

    Say in the case of using a UITableViewController you would load your table cell nibs in viewDidLoad but not actually instantiate them until you needed a cell of that type in -tableView:cellForRowAtIndexPath:.

提交回复
热议问题