0

Well I have some troubles with initialisation class properties in objective c. I have read a lot information but I didn't find answer to my question. So I give example. 1)

//Ex_1.h
@interface Ex_1: UIView {
   IBOutlet UIButton *playBut;
}

@property(retain, nonatomic) IBOutlet UIButton *playBut;
-(void) method1;

@end

//Ex_1.m
@implementation Ex_1
@synthesize playBut;

-(id) initWithFrame:(CGRect)frame {
  self = [super initWithFrame : frame];
  if (self != nil)
      playBut = [UIButton buttonWithType:UIButtonTypeRoundedRect]; //retainCount of playBut = 1;
  return self;

}

-(void) method1 {
   [playBut setTitle:@"pause" forState:UIControlStateNormal];
}

@end

I main Programm first I init object of Ex_1 and then after some times call method1 of this object ([object method1]) and I get runtime error(error tells me that playBut is dealloc, but I think playBut's retain count = 1). So I have some questions:

  1. Is it possible ?
  2. Why garbage collector dealloces playBut if its retain count = 1?(because I don't call [playBut release];
  3. How do I init class properties?

I familar with C++ and actionScript, but I see first time in my life that garbage collector dealloced class property. I use non ARC. It is important for me. Thanks for your attention and answers.

CodaFi
  • 43,043
  • 8
  • 107
  • 153
juramoshkov
  • 7
  • 1
  • 5

2 Answers2

2

[UIButton buttonWithType:] returns an autoreleased object. It will be alive for the lifetime of the scope in which you call it, i.e. initWithFrame: but the autorelease pool can reclaim it after that. You should instead say, in your init selector:

playBut = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];

Then send this in your dealloc:

[playBut release];

Now, if you were to add the playBut as a child to another UIView, that view would retain the child and you wouldn't need to, as long as you only use it during the lifetime of the super view. This is a normal pattern. You could go further and assign a tag to playBut then use viewWithTag: to find your UIButton when you need it.

i_am_jorf
  • 53,608
  • 15
  • 131
  • 222
  • Ok, thank you. But I always get autoreleased object, when I init object ? for example obj = [[Class alloc] init], is it return autoreleased object? – juramoshkov Feb 16 '13 at 17:47
  • If you `new`, `alloc init`, `retain`, or `copy` (NARC) an object, you have to release it. When the name of a method starts with any of those words, it means it's being created for the caller, who has the responsibility to `release` the object when he is done with it. Otherwise the method returned is not owned by the caller (it is created with autorelease), and the caller has to indicate he wants to keep it by calling `retain` on the object. – Jano Feb 16 '13 at 17:56
  • The attribute IBOutlet is used to link the property with a button created in the interface builder. In this case, the button is already retained by the view of the controller as jeff said, so you would write `assign` in your property, instead `retain`. And another thing, you don't need the instance variable or the @synthesize if you are using a modern version of Xcode, just the @property would suffice. – Jano Feb 16 '13 at 18:05
1

You may be confused because your property declaration includes a retain. However you are assigning directly to your iVar here:

      playBut = [UIButton buttonWithType:UIButtonTypeRoundedRect]; //retainCount of playBut = 1;

so not taking advantage of the property setter, so it doesn't retain for you.

So either:

       self.playBut = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 

Or:

       playBut = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain]; 

Of the two, using self.playBut is far better - you should be using properties and their accessors all the time unless you have good reason not to. And no need to declare the iVar separately (or @synthesize these days). See my answer here: Should I declare variables in interface or using property in objective-c arc?

As regards your particular example using UIButtons, they usually get added directly into the UI, which does the retaining for you, so you wouldn't experience this. That's why IBOutlets are normally declared weak (ARC) or assign (nonARC).

Community
  • 1
  • 1
foundry
  • 31,615
  • 9
  • 90
  • 125
  • So, when I work with class property should I access to it with self.property or property(like C++) (I don't talk about initialisation? – juramoshkov Feb 16 '13 at 18:10
  • @user2078865 - I assume you mean _instance_ property. Best to always access via the property, using self. [See my answer here for details](http://stackoverflow.com/questions/14236799/should-i-declare-variables-in-interface-or-using-property-in-objective-c-arc/14236931#14236931) – foundry Feb 16 '13 at 18:12
  • Yes, I mean instance property. Ok. – juramoshkov Feb 16 '13 at 18:15
  • 1
    @user2078865 - Also best to use ARC whenever you can! – foundry Feb 16 '13 at 18:16