Objective-c properties for primitive types - objective-c

In Objective-C Does it ever make sense to specify a property for a primitive type as nonatomic?
I'm wondering about the difference between these two properties:
#property (nonatomic) BOOL myBool;
#property BOOL myBool;

The answer is technically YES they're different, but practically NO they're not, unless you code your own accessors.
Let me explain. For an object pointer property, say #property NSObject *foo there is a clear and important difference in the code that gets generated if you use synthesize the accessors. This is described in the Apple documentation where it points out that the synthesized accessors will lock the object if the property is atomic (if you don't specify nonatomic, it becomes atomic by default)
So for object properties In a very crude nutshell: nonatomic is faster but not threadsafe, atomic (you can't specify it, but its the default) is threadsafe but potentially slower.
(Note: if you're accustomed to Java, you can think of using nonatomic as like not specifying synchronized, and not specifying nonatomic as like specifying synchronized. In other words atomic = synchronized)
But a BOOL is a primitive - in fact a C signed char, so access should be atomic without locking the object as mentioned in Jano's answer. So when you're synthesizing the accessor, there are two possibilities:
1: the compiler is smart and sees that the property is primitive and avoids locking it, and
2: the compiler always locks the object for atomic properties
As far as I can see this is not documented anywhere, so I tried it by using the Generate->Assembly option in XCode and comparing it. The answer was not completely conclusive, but close enough to say that I'm almost certain the answer is #1, the compiler is smart. I say this, because the assembly code generated for an atomic object property is considerably different (more of it) than for a non-atomic object property: this is all the code for locking the object. For a BOOL property on the other hand, there was only one line different - a single "mov" which doesn't look like it could possibly make a difference. Still I wonder. Interestingly, another difference is that the atomic version of BOOL has some extra commented-outlines for debugging - so the compiler is clearly treating it differently.
Nonetheless the similarity is such that I would say they're the same for practical purposes.
But they're still technically different and may be substantively different in some other library you're reading (that you didn't code yourself) if you can't see the implementation, and here's why: atomic properties have a contract. The contract says: "If you access my value on multiple threads, I promise that each setting or getting operation will complete before any other begins".
But, you say, BOOL is still naturally atomic, so isn't this contract implicit?
No. A BOOL variable is naturally atomic, but we're talking about a property. A property might not be synthesized and might not even have a single variable to back it up. This is actually pretty common. Consider:
#property (getter=isEmptyThingo) BOOL emptyThingo;
...
- (BOOL)isEmptyThingo
{
Thingo *thingo = [self deriveTheThingo];
if ([thingo length] == 0) {
return YES;
}
return NO;
}
who knows what's going on in deriveTheThingo!?
Okay, this is a bit contrived, but the point is that isEmptyThingo - our getter doesn't look very atomic, does it? What happens if one thread is deriving the thingo and another thread comes calling to find if its empty.
Long story short: the property is not atomic. So we should declare it so.
Hence m original answer qualified: if you're writing this property yourself and using #synthesize, then they're probably the same, but you should generally not treat them the same.
As a rule of thumb, if you don't need multithreaded support - which you generally don't if you're working in UI code like UIViewControllers, then just declare it all nonatomic.

In a x-bit architecture (eg: 32bit, 64bit, etc.) any value which is x or less bits will always be read or written atomically. This is a property of any sane hardware implementation.
The default atomic property means that a property value is always set or get in whole, disregarding what other threads are doing. This is only a concern for properties that exceed the number of bits of the architecture. Nonatomic is completely ignored by the compiler on any other type.
Example:
#property struct { int d; } flag;
#property (atomic) struct { float x; float y; } point;
#property (atomic,copy) NSString *s;
struct { int d; } is already atomic so the accesors don't need mutual exclusion.
struct { float x, float y} could be in an inconsistent state if it wasn't atomic. Example: two threads setting {1,2} and {3,4} could overlap the writing, and the struct could end up with a value from each set: {1,4}.
Pointers are stored in a single memory position but they require several statements for memory management.
Atomic properties contribute to thread safety avoiding race conditions that lead to inconsistent values or memory management mishaps. This alone doesn't guarantee thread safety because it doesn't deal with other problems like deadlock, starvation, visibility, etc.

Yes. nonatomic is not a memory-management keyword, it has to do with thread safety. Also, properties are atomic by default (without explicitly declaring them as nonatomic), so there is a difference between the two declarations you listed.

Related

What data type do ivars for primitive properties have?

I am asking because the I was dabbling into some complicated block code and I did not expect the following code to work properly.
Say we have a BOOL property, as so:
#property (nonatomic, assign) BOOL isCancelled;
It's auto synthesised, no custom getter, no setter, no explicit ivar.
Then, there's this code... which works perfectly
dispatch_async(queue, ^{
id result = block(&_isCancelled);
if (!_isCancelled) { ... }
}
However, I would have expected it work for the block() call, but not for the if, where I thought it would capture the value of _isCancelled and keep it const, not have it mutate throughout execution. Still, at runtime, the value of _isCancelled is always consistent inside/outside the block, as if it were actually BOOL *
Can anyone explain what's going on?
When declaring a property BOOL cancelled the autosynthesized ivar is BOOL _isCancelled. This is a primitive variable, not a pointer.
However, when a block is capturing ivars, it is actually capturing self, not the ivar itself. Reading ivar _isCancelled actually means reading self->_isCancelled.
Therefore, ivars are not captured by value unless you save them into a local variable first (e.g. BOOL isCancelled = _isCancelled).
See Block automatic retaining, does it affect even to ivars in self? for more information.
TL;DR: The same type as the property.
All object pointers and primitive types are scalar values - i.e. singular values. They all need to be stored at an address in memory and therefore they all have memory addresses of their own.
By passing &_isCancelled, you're passing the address of the BOOL variable, so the block() has been "let in on a secret" - i.e. the location of the BOOL - so it can update it. Then afterwards you're checking the resultant actual value of _isConnected. This works for primitive types (scalars) and object pointers (also scalars).
Whether its a property or not is irrelevant.

Why are some properties and variables in Objective C initialized with a pointer while others are not?

Coming from Java et al, I'm not clear on the difference between these two declarations:
#property (nonatomic, readwrite) NSInteger score;
#property (nonatomic, strong) NSMutableArray *cards;
Why is the pointer, *, not a requirement on both property declarations?
I've seen this a lot in local variables too:
- (void)viewDidLoad
{
[super viewDidLoad];
int foo = 1;
NSString *bar = #"foo";
}
What's the difference between static allocation of primitive type int and NS types?
Objective-C objects are always allocated on the heap, so you always access them through pointers. Variables of primitive (or struct) types can be, and typically are, allocated on the stack and accessed without pointers.
If you're familiar with Java, it's basically the same semantics. Primitive types are accessed and passed around by value, objects by reference. The difference is that ObjC has (by virtue of its C lineage) syntax explicitly marking that difference.
Type names that start with an uppercase prefix in Apple frameworks aren't all ObjC classes. NSInteger is a primitive type just like int, so you can and usually do use it without pointers.
pointer is always used for referring to something at the heap but not when you referring to something on the stack.But
for some primitive types and simple structure which are accessed via the stack so you don't need to use pointer..
NSInteger is a primitive type, that means it will be stored locally on the stack. there is no need to use a pointer to access it, but if you want to use pointer then you can.
You can have a pointer to an NSInteger if you really want to with following way:
NSInteger *pointerToProcessID = &yourNsintegervar;
If you look at the definition of NSInteger you'll see that it is a typedef for a simple integer. Basically, all the non-object types are stored as simple values, while the types that are complex objects are typically pointer properties. There are a couple reasons why these more complex objects are stored as pointers:
Using the value, itself, instead of the pointer would require copying (that is, if you use a pointer, you can put the object somewhere else and you only need to copy the much shorter address rather than all of the content that happens to be in that object, and hence it is more efficient that way).
When using a non-pointer type, it is necessary to know the required storage space, which works if you know the exact type of the object, but fails in the case of inheritance (e.g. an NSMutableArray may add additional fields to NSArray, for example. If you were to use NSArray instead of NSArray*, then assigning from an NSMutableArray would be broken, because the system would only have set aside enough space for the fields in the base class and not for the derived class. When using a pointer, however, since the pointer size is the same for both the base and derived types, one can assign the pointer for a derived type to a pointer to the base type, and still have things work correctly).
Note that it is possible and safe to use a pointer type with these primitive types, as well; however, this is not done for efficiency reasons (it would create additional allocation and dereferencing where not necessary).

Is it OK to have a method's variable with the same name as a declared property?

I understand this is probably bad practice, but I was just curious as to whether or not this has any negative side-effects, in Objective-C (trying to learn as much as I can):
#interface MyClass ()
// Declare a string called 'foo'
#property (nonatomic, strong) NSString *foo
#end
#implementation MyClass
...
- (void)modifyFoo {
// Create a local variable with the same name as a property
NSString *foo = #"Hello!" // No compiler warnings?
self.foo = foo; // <---- Is this OK?
}
This will not throw up a warning in the compiler, and sure enough, my code works as normal. If there are zero negative side-effects, does the type of property, e.g. weak/strong/assign, etc, have an influence on whether or not this is OK?
Note: I am aware that this will not work when the property is synthesised.
This is fine and is my personally preferred approach. The reason no compiler warning is generated is that the instance variable is actually named _foo. This is done by the auto-synthesise added by the compiler (it generates #synthesize foo = _foo for you). Maintaining naming consistency aids clarity.
The main potential side effect is that you inadvertently add / fail to add self. and end up trying to message nil.
Firstly:
this will not work when the property is synthesised.
Huh? Why not?
Actually, it's "OK" in the sense that it works. Actually, there's no ambiguity when you use the self keyword and the dot notation to access your property. If, however, you had an instance variable with the same name as your local variable, then the object with a narrower scope (the local variable in this case) hides the one with a wider scope (the ivar). And that may be undesirable. As far as I know, it even results in a compiler warning. Furthermore, it's hard to get it wrong and decreases overall code readability, so don't do this if you have that identically named instance variable.
If I recall correctly, recent versions of the clang/LLVM toolchain automatically synthesize properties for you, and the name of the backing ivar for a property is preceded by a leading underscore, so this should not be a problem.

Does Apple Provide default implementation of isEqual:

In C there is a default implementation of equality operator. Go through all the member and verify that they satisfy the equality operator. The default is somewhat stupid because if an object contains pointer then the equality operator of the member would be performed on the pointer.
Still, it's good enough for my purpose.
So does it?
Or are we expected to implement isEqual and the corresponding hash for everytime we create a custom object that may we want to use isequal for.
It seems to me the "default" implementation is to simply compare the pointer of the object and not it's member. Am I correct here? It's even worse than C++ standard comparison. That's what I want to verify.
It seems to me if our class is the immediate children of NSObject then isEqual will simply call it's parent's isEqual and that simply compare pointers.
Am I correct here? I am just wanting to make sure of that.
I think that NSObject’s implementation does pointer comparison, and various other classes from the SDK do what’s most appropriate, ie. NSString does comparison on string contents, NSArray compares content equality, and so on. If you want to have “better” equality defined for your custom objects, you have to decide about the semantics and implement it yourself.
Its a little confusing because of the way Apple separates their docs between protocols and interfaces.
#protocol NSObject
- (BOOL)isEqual:(id)object;
This is a required method to be implemented so NSObject (the class) definitely implements this although you wouldnt know it from looking at the class definition on apples dev site. This is directly from the headers in xcode.
In general without implementing a custom isEqual you will expect to only get pointer identity and thats ok in many cases. Systems need to be designed around the way you identify unique instances regardless of the peculiarity of a particular feature such as hash and isEqual. If you need to test for object equality beyond the pointer then you just have to do that.
As NSObject provides isEqual:, and all your objects are descendants of NSObject, then the the simple answer is that a default implementation is provided.
Now you are concerned over the algorithm this default uses, and in a comment write "I wouldn't be sure simply by testing". Let's look at testing, just for fun ;-)
Now isEqual: is a rather fundamental method, if Apple decided to change its semantics the consequences could be significant and not good. So while Apple is free to change how it is implemented provided the semantics remain the same, which means the same objects compare equal after the change as before. Now you've mentioned three possible algorithms isEqual: could use:
Pointer comparison - is it the exact same object
Shallow comparison - do the fields of the object have the same value compared directly
Deep comparison - do the non-pointer-valued fields compared directly have the same value, and do the pointer-valued fields compare equal using isEqual:
These all have different semantics, whichever one Apple has chosen it can't change without breaking a lot of code. And different semantics means you can test...
Coding as I type, errors expected! Only important bits included:
#implementation A
- (BOOL) isEqual:(id)other
{
NSLog(#"A.isEqual called");
return self == other; // true iff same object
}
#end
#interface B
#property (readwrite) int anInteger;
#property (readwrite) A *anA;
#end
#implementation B
#synthesize anInteger, anA;
#end
// Let's test the algorithm
A *myA = [A new];
B *bOne = [B new];
B *bTwo = [B new];
bOne.anInteger = 42;
bOne.anA = myA;
bTwo.anInteger = 42;
bTwo.anA = myA;
// What output is produced (all of it!)
NSLog(#"[bOne isEqual:bTwo] -> %#", [bOne isEqual:bTwo] ? #"Yes" : #"No");
HTH a little.

Why would you use an ivar?

I usually see this question asked the other way, such as Must every ivar be a property? (and I like bbum's answer to this Q).
I use properties almost exclusively in my code. Every so often, however, I work with a contractor who has been developing on iOS for a long time and is a traditional game programmer. He writes code that declares almost no properties whatsoever and leans on ivars. I assume he does this because 1.) he's used to it since properties didn't always exist until Objective C 2.0 (Oct '07) and 2.) for the minimal performance gain of not going through a getter / setter.
While he writes code that doesn't leak, I'd still prefer him to use properties over ivars. We talked about it and he more or less sees not reason to use properties since we weren't using KVO and he's experienced with taking care of the memory issues.
My question is more... Why would you ever want to use an ivar period - experienced or not. Is there really that great of a performance difference that using an ivar would be justified?
Also as a point of clarification, I override setters and getters as needed and use the ivar that correlates with that property inside of the getter / setter. However, outside of a getter / setter or init, I always use the self.myProperty syntax.
Edit 1
I appreciate all of the good responses. One that I'd like to address that seems incorrect is that with an ivar you get encapsulation where with a property you don't. Just define the property in a class continuation. This will hide the property from outsiders. You can also declare the property readonly in the interface and redefine it as readwrite in the implementation like:
// readonly for outsiders
#property (nonatomic, copy, readonly) NSString * name;
and have in the class continuation:
// readwrite within this file
#property (nonatomic, copy) NSString * name;
To have it completely "private" only declare it in the class continuation.
Encapsulation
If the ivar is private, the other parts of the program can't get at it as easily. With a declared property, the clever people can access and mutate quite easily via the accessors.
Performance
Yes, this can make a difference in some cases. Some programs have constraints where they can not use any objc messaging in certain parts of the program (think realtime). In other cases, you may want to access it directly for speed. In other cases, it's because objc messaging acts as an optimization firewall. Finally, it can reduce your reference count operations and minimize peak memory usage (if done correctly).
Nontrivial Types
Example: If you have a C++ type, direct access is just the better approach sometimes. The type may not be copyable, or it may not be trivial to copy.
Multithreading
Many of your ivars are codependent. You must ensure your data integrity in multithreaded context. Thus, you may favor direct access to multiple members in critical sections. If you stick with accessors for codependent data, your locks must typically be reentrant and you will often end up making many more acquisitions (significantly more at times).
Program Correctness
Since the subclasses can override any method, you may eventually see there is a semantic difference between writing to the interface versus managing your state appropriately. Direct access for program correctness is especially common in partially constructed states -- in your initializers and in dealloc, it's best to use direct access. You may also find this common in the implementations of an accessor, a convenience constructor, copy, mutableCopy, and archiving/serialization implementations.
It's also more frequent as one moves from the everything has a public readwrite accessor mindset to one which hides its implementation details/data well. Sometimes you need to correctly step around side effects a subclass' override may introduce in order to do the right thing.
Binary Size
Declaring everything readwrite by default usually results in many accessor methods you never need, when you consider your program's execution for a moment. So it will add some fat to your program and load times as well.
Minimizes Complexity
In some cases, it's just completely unnecessary to add+type+maintain all that extra scaffolding for a simple variable such as a private bool that is written in one method and read in another.
That's not at all to say using properties or accessors is bad - each has important benefits and restrictions. Like many OO languages and approaches to design, you should also favor accessors with appropriate visibility in ObjC. There will be times you need to deviate. For that reason, I think it's often best to restrict direct accesses to the implementation which declares the ivar (e.g. declare it #private).
re Edit 1:
Most of us have memorized how to call a hidden accessor dynamically (as long as we know the name…). Meanwhile, most of us have not memorized how to properly access ivars which aren't visible (beyond KVC). The class continuation helps, but it does introduce vulnerabilities.
This workaround's obvious:
if ([obj respondsToSelector:(#selector(setName:)])
[(id)obj setName:#"Al Paca"];
Now try it with an ivar only, and without KVC.
For me it is usually performance. Accessing an ivar of an object is as fast as accessing a struct member in C using a pointer to memory containing such a struct. In fact, Objective-C objects are basically C structs located in dynamically allocated memory. This is usually as fast as your code can get, not even hand optimized assembly code can be any faster than that.
Accessing an ivar through a getter/setting involves an Objective-C method call, which is much slower (at least 3-4 times) than a "normal" C function call and even a normal C function call would already be multiple times slower than accessing a struct member. Depending on the attributes of your property, the setter/getter implementation generated by the compiler may involve another C function call to the functions objc_getProperty/objc_setProperty, as these will have to retain/copy/autorelease the objects as needed and further perform spinlocking for atomic properties where necessary. This can easily get very expensive and I'm not talking about being 50% slower.
Let's try this:
CFAbsoluteTime cft;
unsigned const kRuns = 1000 * 1000 * 1000;
cft = CFAbsoluteTimeGetCurrent();
for (unsigned i = 0; i < kRuns; i++) {
testIVar = i;
}
cft = CFAbsoluteTimeGetCurrent() - cft;
NSLog(#"1: %.1f picoseconds/run", (cft * 10000000000.0) / kRuns);
cft = CFAbsoluteTimeGetCurrent();
for (unsigned i = 0; i < kRuns; i++) {
[self setTestIVar:i];
}
cft = CFAbsoluteTimeGetCurrent() - cft;
NSLog(#"2: %.1f picoseconds/run", (cft * 10000000000.0) / kRuns);
Output:
1: 23.0 picoseconds/run
2: 98.4 picoseconds/run
This is 4.28 times slower and this was a non-atomic primitive int, pretty much the best case; most other cases are even worse (try an atomic NSString * property!). So if you can live with the fact that each ivar access is 4-5 times slower than it could be, using properties is fine (at least when it comes to performance), however, there are plenty of situations where such a performance drop is completely unacceptable.
Update 2015-10-20
Some people argue, that this is not a real world problem, the code above is purely synthetic and you will never notice that in a real application. Okay then, let's try a real world sample.
The code following below defines Account objects. An account has properties that describe name (NSString *), gender (enum), and age (unsigned) of its owner, as well as a balance (int64_t). An account object has an init method and a compare: method. The compare: method is defined as: Female orders before male, names order alphabetically, young orders before old, balance orders low to high.
Actually there exists two account classes, AccountA and AccountB. If you look their implementation, you'll notice that they are almost entirely identical, with one exception: The compare: method. AccountA objects access their own properties by method (getter), while AccountB objects access their own properties by ivar. That's really the only difference! They both access the properties of the other object to compare to by getter (accessing it by ivar wouldn't be safe! What if the other object is a subclass and has overridden the getter?). Also note that accessing your own properties as ivars does not break encapsulation (the ivars are still not public).
The test setup is really simple: Create 1 Mio random accounts, add them to an array and sort that array. That's it. Of course, there are two arrays, one for AccountA objects and one for AccountB objects and both arrays are filled with identical accounts (same data source). We time how long it takes to sort the arrays.
Here's the output of several runs I did yesterday:
runTime 1: 4.827070, 5.002070, 5.014527, 5.019014, 5.123039
runTime 2: 3.835088, 3.804666, 3.792654, 3.796857, 3.871076
As you can see, sorting the array of AccountB objects is always significant faster than sorting the array of AccountA objects.
Whoever claims that runtime differences of up to 1.32 seconds make no difference should better never do UI programming. If I want to change the sorting order of a large table, for example, time differences like these do make a huge difference to the user (the difference between an acceptable and a sluggish UI).
Also in this case the sample code is the only real work performed here, but how often is your code just a small gear of a complicated clockwork? And if every gear slows down the whole process like this, what does that mean for the speed of the whole clockwork in the end? Especially if one work step depends on the output of another one, which means all the inefficiencies will sum up. Most inefficiencies are not a problem on their own, it's their sheer sum that becomes a problem to the whole process. And such a problem is nothing a profiler will easily show because a profiler is about finding critical hot spots, but none of these inefficiencies are hot spots on their own. The CPU time is just averagely spread among them, yet each of them only has such a tiny fraction of it, it seems a total waste of time to optimize it. And it's true, optimizing just one of them would help absolutely nothing, optimizing all of them can help dramatically.
And even if you don't think in terms of CPU time, because you believe wasting CPU time is totally acceptable, after all "it's for free", then what about server hosting costs caused by power consumption? What about battery runtime of mobile devices? If you would write the same mobile app twice (e.g. an own mobile web browser), once a version where all classes access their own properties only by getters and once where all classes access them only by ivars, using the first one constantly will definitely drain the battery much faster than using the second one, even though they are functional equivalent and to the user the second one would even probably even feel a bit swifter.
Now here's the code for your main.m file (the code relies on ARC being enabled and be sure to use optimization when compiling to see the full effect):
#import <Foundation/Foundation.h>
typedef NS_ENUM(int, Gender) {
GenderMale,
GenderFemale
};
#interface AccountA : NSObject
#property (nonatomic) unsigned age;
#property (nonatomic) Gender gender;
#property (nonatomic) int64_t balance;
#property (nonatomic,nonnull,copy) NSString * name;
- (NSComparisonResult)compare:(nonnull AccountA *const)account;
- (nonnull instancetype)initWithName:(nonnull NSString *const)name
age:(const unsigned)age gender:(const Gender)gender
balance:(const int64_t)balance;
#end
#interface AccountB : NSObject
#property (nonatomic) unsigned age;
#property (nonatomic) Gender gender;
#property (nonatomic) int64_t balance;
#property (nonatomic,nonnull,copy) NSString * name;
- (NSComparisonResult)compare:(nonnull AccountB *const)account;
- (nonnull instancetype)initWithName:(nonnull NSString *const)name
age:(const unsigned)age gender:(const Gender)gender
balance:(const int64_t)balance;
#end
static
NSMutableArray * allAcocuntsA;
static
NSMutableArray * allAccountsB;
static
int64_t getRandom ( const uint64_t min, const uint64_t max ) {
assert(min <= max);
uint64_t rnd = arc4random(); // arc4random() returns a 32 bit value only
rnd = (rnd << 32) | arc4random();
rnd = rnd % ((max + 1) - min); // Trim it to range
return (rnd + min); // Lift it up to min value
}
static
void createAccounts ( const NSUInteger ammount ) {
NSArray *const maleNames = #[
#"Noah", #"Liam", #"Mason", #"Jacob", #"William",
#"Ethan", #"Michael", #"Alexander", #"James", #"Daniel"
];
NSArray *const femaleNames = #[
#"Emma", #"Olivia", #"Sophia", #"Isabella", #"Ava",
#"Mia", #"Emily", #"Abigail", #"Madison", #"Charlotte"
];
const NSUInteger nameCount = maleNames.count;
assert(maleNames.count == femaleNames.count); // Better be safe than sorry
allAcocuntsA = [NSMutableArray arrayWithCapacity:ammount];
allAccountsB = [NSMutableArray arrayWithCapacity:ammount];
for (uint64_t i = 0; i < ammount; i++) {
const Gender g = (getRandom(0, 1) == 0 ? GenderMale : GenderFemale);
const unsigned age = (unsigned)getRandom(18, 120);
const int64_t balance = (int64_t)getRandom(0, 200000000) - 100000000;
NSArray *const nameArray = (g == GenderMale ? maleNames : femaleNames);
const NSUInteger nameIndex = (NSUInteger)getRandom(0, nameCount - 1);
NSString *const name = nameArray[nameIndex];
AccountA *const accountA = [[AccountA alloc]
initWithName:name age:age gender:g balance:balance
];
AccountB *const accountB = [[AccountB alloc]
initWithName:name age:age gender:g balance:balance
];
[allAcocuntsA addObject:accountA];
[allAccountsB addObject:accountB];
}
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
#autoreleasepool {
NSUInteger ammount = 1000000; // 1 Million;
if (argc > 1) {
unsigned long long temp = 0;
if (1 == sscanf(argv[1], "%llu", &temp)) {
// NSUIntegerMax may just be UINT32_MAX!
ammount = (NSUInteger)MIN(temp, NSUIntegerMax);
}
}
createAccounts(ammount);
}
// Sort A and take time
const CFAbsoluteTime startTime1 = CFAbsoluteTimeGetCurrent();
#autoreleasepool {
[allAcocuntsA sortedArrayUsingSelector:#selector(compare:)];
}
const CFAbsoluteTime runTime1 = CFAbsoluteTimeGetCurrent() - startTime1;
// Sort B and take time
const CFAbsoluteTime startTime2 = CFAbsoluteTimeGetCurrent();
#autoreleasepool {
[allAccountsB sortedArrayUsingSelector:#selector(compare:)];
}
const CFAbsoluteTime runTime2 = CFAbsoluteTimeGetCurrent() - startTime2;
NSLog(#"runTime 1: %f", runTime1);
NSLog(#"runTime 2: %f", runTime2);
}
return 0;
}
#implementation AccountA
- (NSComparisonResult)compare:(nonnull AccountA *const)account {
// Sort by gender first! Females prior to males.
if (self.gender != account.gender) {
if (self.gender == GenderFemale) return NSOrderedAscending;
return NSOrderedDescending;
}
// Otherwise sort by name
if (![self.name isEqualToString:account.name]) {
return [self.name compare:account.name];
}
// Otherwise sort by age, young to old
if (self.age != account.age) {
if (self.age < account.age) return NSOrderedAscending;
return NSOrderedDescending;
}
// Last ressort, sort by balance, low to high
if (self.balance != account.balance) {
if (self.balance < account.balance) return NSOrderedAscending;
return NSOrderedDescending;
}
// If we get here, the are really equal!
return NSOrderedSame;
}
- (nonnull instancetype)initWithName:(nonnull NSString *const)name
age:(const unsigned)age gender:(const Gender)gender
balance:(const int64_t)balance
{
self = [super init];
assert(self); // We promissed to never return nil!
_age = age;
_gender = gender;
_balance = balance;
_name = [name copy];
return self;
}
#end
#implementation AccountB
- (NSComparisonResult)compare:(nonnull AccountA *const)account {
// Sort by gender first! Females prior to males.
if (_gender != account.gender) {
if (_gender == GenderFemale) return NSOrderedAscending;
return NSOrderedDescending;
}
// Otherwise sort by name
if (![_name isEqualToString:account.name]) {
return [_name compare:account.name];
}
// Otherwise sort by age, young to old
if (_age != account.age) {
if (_age < account.age) return NSOrderedAscending;
return NSOrderedDescending;
}
// Last ressort, sort by balance, low to high
if (_balance != account.balance) {
if (_balance < account.balance) return NSOrderedAscending;
return NSOrderedDescending;
}
// If we get here, the are really equal!
return NSOrderedSame;
}
- (nonnull instancetype)initWithName:(nonnull NSString *const)name
age:(const unsigned)age gender:(const Gender)gender
balance:(const int64_t)balance
{
self = [super init];
assert(self); // We promissed to never return nil!
_age = age;
_gender = gender;
_balance = balance;
_name = [name copy];
return self;
}
#end
Semantics
What #property can express that ivars can't: nonatomic and copy.
What ivars can express that #property can't:
#protected: public on subclasses, private outside.
#package: public on frameworks on 64 bits, private outside. Same as #public on 32 bits. See Apple's 64-bit Class and Instance Variable Access Control.
Qualifiers. For example, arrays of strong object references: id __strong *_objs.
Performance
Short story: ivars are faster, but it doesn't matter for most uses. nonatomic properties don't use locks, but direct ivar is faster because it skips the accessors call. For details read the following email from lists.apple.com.
Subject: Re: when do you use properties vs. ivars?
From: John McCall <email#hidden>
Date: Sun, 17 Mar 2013 15:10:46 -0700
Properties affect performance in a lot of ways:
As already discussed, sending a message to do a load/store is slower than just doing the load/store inline.
Sending a message to do a load/store is also quite a bit more code that needs to be kept in i-cache: even if the getter/setter
added zero extra instructions beyond just the load/store, there'd be a
solid half-dozen extra instructions in the caller to set up the
message send and handle the result.
Sending a message forces an entry for that selector to be kept in the method cache, and that memory generally sticks around in
d-cache. This increases launch time, increases the static memory
usage of your app, and makes context switches more painful. Since the
method cache is specific to the dynamic class for an object, this
problem increases the more you use KVO on it.
Sending a message forces all values in the function to be spilled to the stack (or kept in callee-save registers, which just means
spilling at a different time).
Sending a message can have arbitrary side-effects and therefore
forces the compiler to reset all of its assumptions about non-local memory
cannot be hoisted, sunk, re-ordered, coalesced, or eliminated.
In ARC, the result of a message send will always get retained, either by the callee or the caller, even for +0 returns: even if the
method doesn't retain/autorelease its result, the caller doesn't know
that and has to try to take action to prevent the result from getting
autoreleased. This can never be eliminated because message sends are
not statically analyzable.
In ARC, because a setter method generally takes its argument at +0, there is no way to "transfer" a retain of that object (which, as
discussed above, ARC usually has) into the ivar, so the value
generally has to get retain/released twice.
None of this means that they're always bad, of course — there are a
lot of good reasons to use properties. Just keep in mind that, like
many other language features, they're not free.
John.
The most important reason is the OOP concept of information hiding: If you expose everything via properties and thus make allow external objects to peek at another object's internals then you will make use of these internal and thus complicate changing the implementation.
The "minimal performance" gain can quickly sum up and then become a problem. I know from experience; I work on an app that really takes the iDevices to their limits and we thus need to avoid unnecessary method calls (of course only where reasonably possible). To aid with this goal, we're also avoiding the dot syntax since it makes it hard to see the number of method calls on first sight: for example, how many method calls does the expression self.image.size.width trigger? By contrast, you can immediately tell with [[self image] size].width.
Also, with correct ivar naming, KVO is possible without properties (IIRC, I'm not an KVO expert).
Properties vs. instance variables is a trade-off, in the end the choice comes down to the application.
Encapsulation/Information Hiding This is a Good Thing (TM) from a design perspective, narrow interfaces and minimal linkage is what makes software maintainable and understandable. It is pretty hard in Obj-C to hide anything, but instance variables declared in the implementation come as close as you'll get.
Performance While "premature optimisation" is a Bad Thing (TM), writing badly performing code just because you can is at least as bad. Its hard to argue against a method call being more expensive than a load or store, and in computational intensive code the cost soon adds up.
In a static language with properties, such as C#, calls to setters/getters can often be optimised away by the compiler. However Obj-C is dynamic and removing such calls is much harder.
Abstraction An argument against instance variables in Obj-C has traditionally been memory management. With MRC instance variables require calls to retain/release/autorelease to be spread throughout the code, properties (synthesized or not) keep the MRC code in one place - the principle of abstraction which is a Good Thing (TM). However with GC or ARC this argument goes away, so abstraction for memory management is no longer an argument against instance variables.
Properties expose your variables to other classes. If you just need a variable that is only relative to the class you're creating, use an instance variable. Here's a small example: the XML classes for parsing RSS and the like cycle through a bunch of delegate methods and such. It's practical to have an instance of NSMutableString to store the result of each different pass of the parse. There's no reason why an outside class would need to ever access or manipulate that string. So, you just declare it in the header or privately and access it throughout the class. Setting a property for it might only be useful to make sure there are no memory issues, using self.mutableString to invoke the getter/setters.
Backwards compatibility was a factor for me. I couldn't use any Objective-C 2.0 features because I was developing software and printer drivers that had to work on Mac OS X 10.3 as part of a requirement. I know your question seemed targeted around iOS, but I thought I'd still share my reasons for not using properties.