Using NSSet/allTargets to get the xib so-called "File owner"?

154 views Asked by At

Looking at this image, you can see that a UIView loaded from a nib has a "File Owner"

enter image description here

Notice in the xib, Apple has labelled something "File Owner".

So, open Xcode, open any xib, look at Placeholders, and look directly underneath, to see:

"File Owner".

In this particular example, the "xib-file-owner" happens to be the class LoginScreen.

So, at run time, for a specific thing created by this xib, the "was-xib-file-owner" (to coin a phrase) will in fact be:

It will be: some particular instance of the class LoginScreen.

Now at run time. Obviously, in a UIView, with every UIButton, you can simply call

[self.someButton sendActionsForControlEvents:UIControlEventTouchUpInside ];

and you get to indeed "go to", precisely:

You go to: that instance of the class LoginScreen.

{Note - OF COURSE, the UIButton could be pointed anywhere at all. I am asking about the case where we know for a fact the UIButton is indeed pointing to the "was-xib-file-owner" of the UIButton.}

In fact, the method allTargets will indeed return that target (in this case some instance of the class LoginScreen) as part of the N target(s) it returns, and indeed the selector(s), etc etc.

I'm not good enough to write code for allTargets, NSSet, etc.

Can someone show me how to extract, using allTargets and some computer code, the instance of the class LoginScreen? ie the running instance of the "was-xib-file-owner" seen in the xib? Cheers.


Later:

bizarrely, the answer to this question is, essentially and generally:

[self.allTargets anyObject]

since, if created from the xib there will only be the one, and, it is precisely what is described in bold above. To repeat: OF COURSE, the UIButton could be pointed ANYWHERE AT ALL. I am asking about the case where we know for a fact the UIButton is indeed pointing to the "was-xib-file-owner" of the UIButton.

In that ("normal") case the answer is indeed just that surprisingly simple -- [self.allTargets anyObject].

3

There are 3 answers

4
Daij-Djan On BEST ANSWER

there is no file owner (as seen in IB) known to views at runtime. The information about the file owner isn't there. Closest you can do is check the target's class:

    if([self respondsToSelector:@selector(allTargets)]) {
        NSSet *owners = self.allTargets;
                    for(id owner in owners) {
                        if([owner isKindOfClass:[UIViewController class]])
                           NSLog(@"owner: %@", owner);
                    }
            }

or just assume target is owner

    if([self respondsToSelector:@selector(allTargets)]) {
        id owner = [self.allTargets anyObject];
        NSLog(@"owner: %@", owner);
    }
2
Geraud.ch On

Actually there is no "owner" for a button.

A UIButton is a subview of a specific view, in IB, you drag your button in a certain view and then the button becomes a subview of this view. To retrieve the superview of the button, you call [myButton superview];

Then a Button can be referenced as a property or iVar of a certain class but it's something else.

4
simeon On

You have a UIButton, and it has targets attached for certain control events (commonly UIControlEventTouchUpInside).

You can fetch the targets of a UIButton as follows

NSSet *targets = [myButton allTargets];

for( NSObject *target in targets )
{
    //Do something with target

    //Maybe it's a view:
    if( [target isKindOfClass:[UIView class]] )
    {
        //Do something to view specific target
    }
}

It is important to note two things:

Targets are not the "owners" of a UIButton, nor do they need to be UIViews (if I understand your question correctly). Targets can be any object, generally they will be derived from NSObject.

"File's Owner" in Interface Builder is just a term for the UIViewController (generally) which "owns" the nib — it may or may not be the target of the button!

If you know for certain that your button has your File's Owner as a target, then you can check for it in the following way (though I would not recommend coding like this):

//Assuming your File Owner is "LoginScreen" as in your picture
NSSet *targets = [myButton allTargets];

for( NSObject *target in targets )
{
    //Is the target our File Owner class type?
    if( [target isKindOfClass:[LoginScreen class]] )
    {
        LoginScreen *login = (LoginScreen *)target

        //Do something with `login` 
    }
}

A better way would be to recursively check the nextResponder of your UIButton until you hit your managing view controller. I haven't tested the following code, but it follows the documentation:

UIResponder *responder = [myButton nextResponder];

while( [responder isKindOfClass:[UIViewController class]] == NO &&
       responder != nil )
{
    responder = [responder nextResponder];
}

//If your button is "owned" in the responder chain
// by a UIViewController, then `responder` will be it
// otherwise `responder` will be nil
if( responder )
{
    //Do something
}

I don't know why you need to do this, however. Perhaps there is a simpler solution to your problem?