Objective-C property attributes best practices

@rmaddy's answer is a good one.

I would add the following.

If you are creating (or have inherited) classes that interoperate with Swift, it is very useful to include nullable or nonnull property attributes. If you add it in any part of a header file, you will need to specify it for all parts of the header file (compiler warnings will help you). It's even quite useful for Objective-C callers to know from the method signature what may and may not be a nil value.

Another property of note is class. You can add a property to the class.

Adding these two items together, and if you are implementing a singleton,

+ (MyClass *)sharedInstance;

it's quite useful to define it as a property:

@property (class, nonatomic, nonnull, readonly) MyClass *sharedInstance;

(In which case you are required to add a backing variable for it as described in this article)

This will let you access the shared instance via dot notation.

[MyClass.sharedInstance showMeTheMoney:YES];

And in Swift, the rather annoying

MyClass.sharedInstance()?.showMeTheMoney(true)

turns into

MyClass.sharedInstance.showMeTheMoney(true)

‡ maybe it's just 3 characters to you, but it keeps my head from exploding mid-day.


Edit: I would add, try out

+ (instancetype)shared;

This 1) shortens the naming to concur with modern Swift convention, and 2) removes the hardcoded type value of a (MyClass *).


1a) The default attributes for a property are atomic, and strong (for an object pointer) or assign (for a primitive type), and readwrite. This assumes an all ARC project.

So @property NSString *string; is the same as @property (atomic, strong, readwrite) NSString *string;. @property int value; is the same as @property (atomic, assign, readwrite) int value;.

1b) Attributes are grouped as follows:

  • atomic/nonatomic
  • strong/weak/assign/copy
  • readwrite/readonly

Pick one and only one from each of those three groups.

Actually, the latest Objective-C adds support for nullable/nonnull with the default being nullable.

2) General rules are as you say.

  • Object pointers should usually be strong.
  • Primitive types should be assign.
  • weak should be used in child/parent references to avoid reference cycles. Typically the parent has a strong reference to its children and the children have a weak reference to their parent. Delegates are typically weak for the same reason.
  • copy is typically used for NSString, NSArray, NSDictionary, etc. to avoid issues when they are assigned the mutable variant. This avoids the problem of the value being changed unexpectedly.
  • There's a big "gotcha" using copy with NSMutableString, NSMutableArray, etc. because when you assign the mutable value to the property, the copy attribute results in the copy method being called which gives back a non-mutable copy of the original value. The solution is to override the setter method to call mutableCopy.

3) Using the wrong attribute could have serious problems depending on the needs of the property and the attribute being used.

  • Using assign instead of strong for an object pointer is probably the worst mistake. It can lead to app crashes due to trying to access deallocated objects.

  • Using nonatomic instead of atomic on a property that will be accessed concurrently on multiple threads may lead to really hard to find bugs and/or crashes.

  • Using strong instead of copy for NSString or NSArray (and other collections) can possibly lead to subtle and hard to find bugs if mutable variants were assigned to the property and other code later modifies those values.