Adam Jones
Adam Jones

Reputation: 785

Creating an instance of an instance of another class

I'm trying to break some of my "super objects" into more manageable classes that have single (or at least limited) responsibility.

One problem I've just run into is making an object of a specific instance of a UIBarButtonItem. In the class it is in now I first define a UIButton, and then all of the images that act as icons for that button as subviews (for instance the button represents access/control to a device, and I use the button image to show the current signal strength of that device). Also that button is listening for NSNotifications from the device object to represent the signal strength changing, or if the device disconnects. And pressing the button sends a message to the device to disconnect. All of this code works perfectly fine now as a property of the RootViewController. However, I want to pull it out into its own class as the button is shared by several classes, and it just clutters up the controller with unnecessary methods.

I tried making an separate class with an init like below. However, this doesn't work as the self used for the button isn't the same self that is ultimately created by [UIBarButtonItem alloc] and when either the NSNotification or the button press try to send a message to the selector of "self", that object has already been dealloced. The problem is, I'm not sure how to create a object (as defined by the class) that is just an instance of another class, as opposed to a property of an object (as it currently is for the RootViewController).

Edit and additional explanation of my problem

MyClass is currently subclass of UIBarButtonItem. However, I'm not trying to use it like this: [[MyClass alloc] initWithCustomView:]. I want [MyClass alloc] init] by itself to completely create the custom view - in other words the whole point of this class is to completely contain all that is necessary for this button to create itself, manage its subviews, and take the appropriate action when it is pressed. (I could easily make MyClass an NSObject with a public method like [MyClass setupButton] and a public property of type UIBarButtonItem. However, I think that looks wrong because then the class is only there to create the button, but it is not the button itself.)

@interface MyClass : UIBarButtonItem
@end

@implementation MyClass
- (id)init {
    if (self = [super init]) {

        UIImage *defaultButton = [[UIImage imageNamed:@"...
        UIImage *defaultButtonPressed = [[UIImage imageNamed:@"....
        UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 40, 30)];
        [button setBackgroundImage:defaultButton forState:UIControlStateNormal];
        [button setBackgroundImage:defaultButtonPressed forState:UIControlStateHighlighted];
        [button addTarget:self action:@selector(deviceButtonPressed) forControlEvents:UIControlEventTouchUpInside];

        //Then several UIImageViews that are added as subviews of the button, initially hidden

        //Then set up the NSNotification listener

        //Finally
        self = [[UIBarButtonItem alloc] initWithCustomView:button];
    }

    return self;
}

//Then several functions to handle hiding and unhiding the subviews depending on the received device notifications, and a function to handle the button press and sending the message back to the device.

Upvotes: 0

Views: 133

Answers (2)

jscs
jscs

Reputation: 64002

This is not how initialization works in Cocoa. Please read "Initialization" in the Cocoa Core Competencies guide.

Your object has already been allocated when this init method is run. You should not be reassigning the self pointer to another allocation.

Your class should first call its superclass's designated initializer self = [super initWithWhatever:obj];, then set up its own properties.

Upvotes: 1

Alexis King
Alexis King

Reputation: 43842

It seems to me that you want to extend UIBarButtonItem, not create an instance of it in your init method. Try changing your class declaration (in your class's .h file) from this:

@interface MyClass : NSObject

to this:

@interface MyClass : UIBarButtonItem

Then just return self in your init method. Setting self to a value is usually a bad idea.

If you're unsure about what's going on here, you're creating a subclass of UIBarButtonItem. This lets your subclass extend the superclass's functionality. If you're confused, you should take a look at subclassing/class inheritance in object-oriented languages to understand what's going on. This guide documents how classes work in Objective-C.

Upvotes: 1

Related Questions