8

Are we supposed to convert all of our instance variables we wish to retain to private properties or am I missing something obvious?

@interface SomethingElse : Something  {

    NSMutableArray *someArray;

}

In this example, someArray is initialized in a method with [NSMutableArray initWithObject:someObject] but isn't retained.

My particular situation is I'm updating a game, there are a lot of instance variables, so I want to make sure I'm doing this right for the sake of future versions of the sdk.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Bill Kervaski
  • 542
  • 6
  • 17

6 Answers6

19

Are we supposed to convert all of the local variables we wish to retain to private properties or am I missing something obvious?

First, the variable you showed in your example is an instance variable, not a local variable. Local variables are declared inside a block of code (e.g. inside a function or method, or inside some sub-block such as the body of a conditional statement) and have a lifetime that's limited to the execution of the block in which they're declared. Instance variables are declared in a class; each instance of that class gets its own copy of the instance variables declared by the class.

Second, no, you don't need to convert all your instance variables to properties. Instance variables are treated as strong references by default under ARC. A property is really just a promise that a class provides certain accessors with certain semantics. Just having an instance variable doesn't mean that you have to provide accessors for that ivar. (Some might say that you should, but you don't have to.)

Cœur
  • 37,241
  • 25
  • 195
  • 267
Caleb
  • 124,013
  • 19
  • 183
  • 272
  • Thanks, edited question to correctly reflect instance variables. I have read that instance variables default to strong, but in my example the object is being dereferenced (i.e., BAD_ACCESS), which is what prompted me to post this as now I'm confused. – Bill Kervaski Jul 03 '12 at 16:18
3

A @property is the same as an instance variable unless you use other than the default storage modifier, which is strong for objects. Example, if you want @property (copy) NSString *s; either use an instance variable and remember to call copy each time you set the variable, or use the @property (which is easier).

Jano
  • 62,815
  • 21
  • 164
  • 192
  • This is really the only situation that using `@property` makes sense of a private variable, as any use of `@property` already creates a variable. +1. – Richard J. Ross III Jul 03 '12 at 16:13
1

ARC's version of retain is called strong.

Basically, you would declare it using something like:

@property (strong) NSMutableArray *someArray;

See What does the "strong" keyword do for details.

It's generally better to use properties instead of local variables, because the properties get you accessors/setters for "free", and are generally easier to use.

Community
  • 1
  • 1
houbysoft
  • 32,532
  • 24
  • 103
  • 156
  • Thanks, and I understand how ARC works with properties, but my question is really to determine if now local variables should be replaced with private properties (if we want to retain them)? – Bill Kervaski Jul 03 '12 at 16:03
  • Apple recommends you no longer explicitly declare variables unless you have a need to. Use properties, and, if you need direct access to the iVar, you can set the ivar name when you synthesize the property, e.g.: @synthesize myProperty = __myVariable – isaac Jul 03 '12 at 16:09
  • @BillKervaski it really makes no difference with ARC. – Richard J. Ross III Jul 03 '12 at 16:10
  • -1. This answer fails to point out that there is very little difference between properties and ivars in ARC, as all the memory management is done for you, so you can use either. – Richard J. Ross III Jul 03 '12 at 16:10
  • @RichardJ.RossIII: not true. The main advantage of properties is that you can magically generate accessors/setters, simply by giving various attributes when declaring your property. This goes beyond just memory management. With a property, you can easily make it readonly, set atomicity, make it copy every time you set a new value, etc. Furthermore, for what the OP wants, a @property is better since you can easily make it `strong`. – houbysoft Jul 03 '12 at 16:15
  • @houbysoft a ivar is `__strong` by default, and requires no additional syntax to be able to have it to be able to be set, can be made `volatile` for atomicity, and a readonly `iVar` defeats the purpose of one in the first place. – Richard J. Ross III Jul 03 '12 at 16:17
  • @RichardJ.RossIII: [`volatile != atomic`](http://en.wikipedia.org/wiki/Volatile_variable#In_C_and_C.2B.2B). And if it is `strong` by default, how come the OP says it gets deallocated for him? – houbysoft Jul 03 '12 at 16:20
1

You describe a BAD_ACCESS problem in some of your other comments. There is something else going on here. In ARC, your ivars are strong unless otherwise qualified (and in non-ARC, they're not going to get released on your behalf).

For example, this ARC code works fine, with no BAD_ACCESS as you report in your comments to other answers:

@interface ArcTestViewController ()
{
    NSMutableArray *_someArray;
}
@end

@implementation ArcTestViewController

- (void)dealloc
{
    _someArray = nil;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    _someArray = [[NSMutableArray alloc] initWithObjects:@"Mo", @"Larry", @"Curly", nil];
}

- (IBAction)checkIvarTouchUpInside:(id)sender 
{
    NSLog(@"%s _someArray = %@", __FUNCTION__, _someArray);
}

@end

You might have to show us your example where you're getting your BAD_ACCESS because it has to be something else.

In answer to the "property" or "ivar" question, while I'm sympathetic to the "always use properties" argument, personally I use properties for anything for which I need to provide external accessors and I otherwise use private ivars (not in the .h, but rather in the private interface in the .m file). This makes my public interfaces in my .h files really clean and easy to understand when I return to them months later. If you do adopt a "always use properties" approach, I'd only advise that your public declaration of those properties should be as restrictive as possible (make the property private if you can, make the public declaration of the property readonly if you don't need to provide readwrite access, etc.).

By the way, the Naming Properties and Data Types of the Coding Guidelines for Cocoa is a good reference of best practices.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
0

With Obj-C 2.0 and later, there really seems to be little reason to use iVars. I personally haven't used one in forever. The properties just do everything for you!

anon_dev1234
  • 2,143
  • 1
  • 17
  • 33
  • There are many reasons to use iVars. Top on the list: Much harder for a hacker to come along at runtime with a dylib and mess up your code, allows for easier C-style arrays, and is lighter weight than a property. – Richard J. Ross III Jul 03 '12 at 16:11
  • @RichardJ.RossIII: with regard to iVars security: Does it apply to iOS sandbox environment? – user523234 Jul 03 '12 at 16:57
  • @user523234 yup. Anyone with a jailbroken device can execute code on your executable which you don't want to happen, and that code is much harder to execute when using iVars instead of properties. – Richard J. Ross III Jul 03 '12 at 17:02
  • @RichardJ.RossIII In regards to hackers, are they then able to access a property declared within my implementation (i.e. non-public properties)? – anon_dev1234 Jul 03 '12 at 17:57
  • @bgoers yes, they can. They can do exactly the same with variables, it's just a bit harder to do. If you need safety like that, use C++ – Richard J. Ross III Jul 03 '12 at 18:01
  • @RichardJ.RossIII Hmmm well then I stand corrected. I guess I didn't mean iVars were useless, but you learn something new everyday! So how exactly do iVars make it more difficult to execute malicious code on (when compared to properties) – anon_dev1234 Jul 03 '12 at 18:05
  • @bgoers memory management, from an external source, in a nutshell. This is not the best place to explain it, however. – Richard J. Ross III Jul 03 '12 at 18:08
0

Thanks all for your responses.

If I call the method that needs the object with (using a cocos2d game engine method):

[self schedule:@selector(someMethod) interval:3.0];

The object is dereferenced, if I call it directly without putting it in the cocos2d scheduler:

[self someMethod];

Then there is still a valid pointer. Just to test, I retained it and it stays around.

So the question is now how do we force a retain to prevent ARC from thinking we're done with it and releasing it?

Changing the instance variable to a private property does it safely so we'll go with this as the answer.

Bill Kervaski
  • 542
  • 6
  • 17
  • Just for clarification - you're saying that switching the ivar to a @property actually fixes the problem? My problem is with objects in NSMutableDictionary that aren't retained. – rrbrambley Jan 10 '13 at 21:10