why would you use #property with NSArray?
The reason for my question is because I was under the impression that #properties were mainly used to take advantage of the getter and setter you get for free when you use #property, but when you assign an NSArray to a property you know you will never use the getter and setter to access the objects in the array, why use properties on this case. Does this have to do with ARC, in other words is this considered a better memory management practice?
You use a property to get or set the whole array. You also use the property to access individual elements of the array.
Using a property with an array has nothing to do with ARC or MRC. Properties are a way to encapsulate data. That's it.
If you don't wish to provide access to the whole array then don't use a property. Add method(s) to set/get individual elements of the internal array if that is appropriate.
Along with what already said by other answers, I usually like to copy my array for security purposes.
If you're accepting an NSArray by the client, she could potentially provide you a NSMutableArray instance. If that's the case and you want to ensure that the array you're working with doesn't change unexpectedly, you'd better copy it as opposed to retain it.
Properties come in handy in this case since you can declare
#property (nonatomic, copy) NSArray * myArray;
and be sure that you're the only owner of that array after you assigned it.
I typically use this strategy for any class with mutable subclasses, such as NSString, NSArray, NSSet and so on, whenever I care about the ownership of the data.
The downside of this strategy is of course memory efficiency, but in the end engineering is the art of intelligent compromise.
To use the array outside of a single method or class. ClassA.array = ClassB.array; or to simply read from the array in a different method of the same class since the array will dealloc immediately after execution.
but when you assign an NSArray to a property you know you will never
use the getter and setter to access the objects in the array, why use
properties on this case.
For the same reasons that you use properties for other objects:
accessors: The accessors are for the array itself, not objects in the array. It's not uncommon to get or set an entire array at once:
NSArray *kids = frank.children; // get the array
mary.children = #[#"Nick", #"Sam", #"Susan"]; // set the array
abstraction: Using properties instead of accessing the underlying array directly makes it easier to change the implementation later, should that become necessary.
KVC compliance: You get it for free with properties. With collections like arrays, KVC gives you a lot of power. You can use collection operators like #avg and #max as well as indexed accessors:
int employees = [accounting countOfEmployees]; // same as [accounting.employees count]
Employee *thirdEmployee = [engineering objectInEmployeesAtIndex:2]; // same as [engineering.employees objectAtIndex:2]
Related
On some intuitive (perhaps wrong) idea of performance, I always get a copy of a mutable instance before I store it. So if a property expects an NSArray I take the mutable array I'm working with and store it as self.array = mutableArray.copy (though the property is specified as strong or retain).
This seems silly to me, suddenly, but is it? Do mutable instances -- doing the exact same task -- perform the same?
Note: The mutable instance falls out of scope and (thanks to ARC) gets released right after this, so there's no worry that it'll be mutated once it's assigned to the property.
NSArray and NSMutableArray are both (as far as I'm aware) implemented on top of CFArray, which simply has a flag specifying whether it's mutable. CFArray functions which require a mutable array have an assertion right at the beginning, checking that flag:
void CFArraySetValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *value) {
// snip...
CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
Mutable and immutable CFArrays are identical other than passing or failing this assertion, and so should NSArrays and NSMutableArrays be, performance- or other-wise.
Partly answered here: NSArray size and mutability
NSMutableArray is not noticeably slower or larger (memory-wise) than an NSArray. It's basically just an NSArray that reallocates itself when it gets full as as bigger array, and keeps doing that as you add items to it.
The reason for copying mutable arrays as immutable ones when assigning them to values in your class is so you can guarantee that their values don't change. If you store a mutable array in your class, other code can change its values outside of your class without calling any of your methods. That leaves you vulnerable to crashes due to internal inconstancy errors within your classes.
For example, supposing that when the array was set, you cached the length of the array as an int property in your class. That would be fine if the array was immutable, but if it was mutable, someone else could change the array, and your cached value would now be wrong, but you have no way of knowing that.
However, it's not necessary to do the copying manually. If you declare your array properties as:
#property (nonatomic, copy) NSArray *foo;
Then whenever you assign an array to object.foo, it will automatically be copied. You don't need to copy it again yourself. It's best practice to use a property type of copy instead of strong/retain for any type that has a mutable variant, like so:
#property (nonatomic, copy) NSArray *foo;
#property (nonatomic, copy) NSString *foo;
#property (nonatomic, copy) NSDictionary *foo;
#property (nonatomic, copy) NSData *foo;
etc...
However be careful not to use it for mutable properties, or it will make an immutable copy stored in a property that thinks it's mutable and cause a crash if you try to mutate it. The synthesised copy property isn't smart enough to use mutableCopy automatically.
#property (nonatomic, copy) NSMutableArray *foo; //don't do this
For clarity you're asking if, given an NSArray and an NSMutableArray both subjected to a battery of non-mutating test methods, does the NSArray perform noticeably faster? I specify non-mutataing, because it looks like you're copying a mutable array to an immutable array with the belief that the immutable array will perform its non-mutating methods faster than the mutable array. Anyways, the answer is no. (But don't take my word for it; profile).
Even if NSMutableArray overrode some non-mutating methods (which we can't know about, one way or another), you wouldn't need to worry about it. Adding a couple CPU cycles is trivial compared to the overall computational complexity of the operation. As long as NSMutableArray doesn't manage to turn a O(n) lookup-operation into a O(n2) operation, you'll be fine 99% of the time. (Those complexities are just fictitious examples).
While there are perfectly valid reasons why you might want to copy a mutable array into an immutable array (as pointed out by #NickLockwood), performance shouldn't be one of them. Premature optimization is very bad, after all.
How would you return an object from a method, so it is read-only for the caller?
Please note that this isn't a property that can be simply set to read-only when it's getter is declared
i.e #property(nonatomic,retain,readonly) NSDate* pub_date;
For example:
-(SomeClass*)getObject
{
SomeClass* object = [[SomeClass alloc] init];
//Don't allow writing to 'object'
return object;
}
Thanks.
Short answer: there's no simple way of doing this.
Longer answer: Apple's framework defines a sort of standard for its collection classes where the immutable collection is the base class and the mutable collection is the inheriting class. So, for example, NSMutableArray inherits from NSArray. You can follow that standard, and have methods that return MyClass to clients while using MyMutableClass inside them. Technically the client can still send the mutating messages, of course, but IMHO that's not a big risk (after all, the client doesn't know your implementation details).
There are other, more complicated options - you can use pointer swizzling, or subclass and override all mutating methods, or simply copy the mutable class into an immutable counterpart (that's not complicated but may incur a performance hit). But for best results you should probably follow Apple's example.
It depends what the object is. If it has a mutable / immutable pair (like NSString/ NSMutableString) then your getter method can return the immutable version.
Otherwise, you can't control the behaviour of other objects - once you've returned an object, there is no control over it from the object that originally provided it.
If you are concerned that another object may alter an object returned from a getter, and thereby amend the property held within the original object, then you should return a copy of the object instead.
Example:
Object A has a mutable string property, object B asks for this mutable string, the getter directly returns the instance variable backing the property.
Object B then changes the string - the property of object A has also been amended because both objects have a pointer to the same mutable string.
In this case, you would return a copy of the object rather than the object itself. If your object is a custom one, you must implement the NSCopying protocol to allow this.
A further note - declaring a property as read only simply means that no setter accessor will be generated - i.e. objectA.property = newValue; will result in a compiler error.
if object has property of type NSString or NSNumber, which is better, retain or copy?
I think these objects are immutable, (can not change state of object) so copy is better?
I see the example why copy is better that assign NSMutableString and change it, but there's no NSMutableNumber. Then in the case of NSNumber, I'd better use retain to NSNumber objects?
If copy is better because NSString and NSNumber has small memory usage, how about if property is NSArray type?
NSArray type is also immutable, what about use copy in NSArray properties?
With immutable objects, copy.
For immutable objects like most NSStrings, -copyWithZone: is effectively
-(id) copyWithZone: (NSZone*) zone
{
return [self retain];
}
so the overhead is minimal.
With mutable objects, probably copy but with large mutable objects like strings and large mutable arrays, you need to make a judgement call based on profiling your code. Also, of course, with mutable objects you might want the original because you might want to see the changes in the original.
Why can you be interested in copying an immutable object? Actually, immutable classes could simply return [self retain] inside the copy method. What I usually do:
Assign for UI outlets and in some other specific references where it's important to avoid retain cycle
Simply retain immutable objects
Copy simple mutable object
Deep copy for the container types (mutable arrays, dictionaries etc.)
Of course, the rules above are not absolute, but in general they work.
If I want to return an immutable array like this + (NSArray *)ids but inside this method I'm declaring a NSMutableArray because I want to sort it using -sortUsingSelector:.
Returning this method works perfect.
But is it "okay" to write code that declares that the return method should be one type and the actually type is another?
Does this work because NSMutableArray is a subclass of NSArray?
Is the actual return value an NSArray or an NSMutableArray?
(…) is it "okay" to write code that declares that the return method should be one type and the actualy type is another?
Yes, it is provided the types are compatible; see the next paragraph. In fact, there are some cases in Cocoa (notably class clusters) that do that as well.
Does this work because NSMutableArray is a subclass of NSArray?
Exactly. Since NSMutableArray is a subclass of NSArray, it inherits all its methods and declared properties, so it publicly behaves like NSArray. This is called the Liskov substitution principle.
Is the actual return value a NSArray or a NSMutableArray?
The return value is whatever you’re returning. Since you’re returning an NSMutableArray, it’s an NSMutableArray. From the caller perspective, it is an object that can be used like an NSArray.
Whether it's "okay" or not is a difficult question. If it's a small project and only you use the code, it might be allright. However, if you rely on nothing being able to change the "NSArray" returned, it's not ok. (See the last point)
Yes.
It's an NSMutableArray. A simple cast will let you change the values in it.
If you actually want to a return an immutable object, do the following:
NSArray* immutableArray = [[mutableArray copy] autorelease];
return immutableArray;
I have 2 questions:
What is the difference between valueForKey: and objectForKey:? Is it that one is for NSDictionarys (objectForKey:) and for others it is valueforKey:, or is it the reverse?
Also what is the difference between valueForKey: and valueForKeyPath:? Has it got something to do with Core Data?
Please help.
valueForKey: is part of the NSKeyValueCoding protocol and is therefore part of the key-value coding framework, which allows you to access class properties by name at runtime. That's how NIBs are loaded, for example — the names of properties associated with connections are loaded and then the values are set directly by name. This contrasts with the way that visual interface design tools often work in other languages, generating lots of hidden statically compiled code.
objectForKey: is defined on dictionaries only, and looks up an object by its key. An NSDictionary is a class that stores connections between values and keys.
So, valueForKey: could be used on an NSDictionary to return meta information about the dictionary, such as the count of objects inside it, the list of all keys, etc. objectForKey: would be used actually to look into the dictionary.
At runtime, the difference is that objectForKey: is a method with a completely opaque implementation. valueForKey: explicitly relies on subsequently calling named getters and setters. The reason for the latter is that you can extend key-value coding to key-value observing, where you ask to be informed every time a particular property on a particular object changes. At runtime that's achieved with a method swizzle, where the original setter is replaced by a new one that calls the previous setter and then sends out the required messages. Because all messages are dispatched dynamically, that's just achieved by modifying tables within the object instance.
So any object that is key-value coding compliant (which just means declaring and implementing your properties in the proper way, which the new-ish #property/#synthesize syntax does automatically) can be observed without the object itself having to implement any code.
There's further Apple stuff that uses key-value coding to achieve various things, including CoreData, but it's not specifically to enable any one other technology.
valueForKeyPath: is like valueForKey: except that it can traverse several objects. So you can have a root object with a bunch of properties, each of those properties is another object with another bunch of properties, etc, and using a key path you can retrieve a value way out at the leaf of that data structure rather than having to iterate through object after object for yourself.
In summary, valueForKey: and valueForKeyPath: provide information about object instances and interact with the dynamic nature of the Objective-C runtime. objectForKey: is a dictionary specific method that does dictionary tasks.
Additions:
An example, coded as I type and assuming that NSDictionary is key-value coding compliant:
NSDictionary *someDictionary;
// create someDictionary, populate it, for example (note: we assume photoOfKeys.jpg
// definitely exists, not a good idea for production code — if it doesn't we'll get
// a nil there and anything after it won't be added to the dictionary as it'll appear
// that we terminated the list):
someDictionary = #{ #"favouriteGarment": #"hat",
#"#allKeys" : [NSImage imageNamed:NSImageNameDotMac],
#(2) : NSArray.new };
NSObject *allKeys;
// we make no assumptions about which type #allKeys will be, but are going to assume
// we can NSLog it, so it needs to be a descendant of NSObject rather than 'id' so as
// to definitely respond to the 'description' message — actually this is just compile
// time semantics, but if someone else reads this code it'll make it obvious to them
// what we were thinking...
// some code to get all of the keys stored in the dictionary and print them out;
// should print an array containing the strings 'favouriteGarment', '#allKeys' and
// the number 2
allKeys = [someDictionary valueForKey:#"#allKeys"];
NSLog(#"%#", allKeys);
// some code to get the object named '#allKeys' from the dictionary; will print
// a description of the image created by loading photoOfKeys.jpg, above
allKeys = [someDictionary objectForKey:#"#allKeys"];
NSLog(#"%#", allKeys);
// `objectForKey is analogous to `objectForKeyedSubscript:`, aka
allKeys = someDictionary[#"#allKeys"];
allKeys is a property of NSDictionary as described here. I've also added a mapping from the NSString allKeys to a photograph of some keys. Whether I use the key-value coding valueForKey: methods or the NSDictionary objectForKey: lookup method dictates whether I read the property of the object instance or whether I send the object instance a message asking it to do its unique job.
objectForKey: is a method on NSDictionary for accessing the object associated with a key. valueForKey: is a method on NSObject for accessing any value associated with any object, through the name of a accessor method, property, and/or instance variable.
valueForKeyPath: can be seen as a shorthand for several calls to valueForKey:. You can think of it as sort of a xpath, if you will.
These two statements will result in the same output:
// Using nested valueForKey:
NSLog(#"%#", [[myObject valueForKey:#"foo"] valueForKey:#"bar"]);
// Can be done with a single valueForKeyPath;
NSLog(#"%#", [myObject valueForKeyPath:#"foo.bar"]);
valueForKey:and valueForKeyPath: are part of KVC (Key Value Coding). Introduction and in-depth documentation can be found here: http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueCoding/
valueForKey: and valueAtKeyPath: are methods defined in the NSKeyValueCoding informal protocol, and default implementations for both are provided by the root class NSObject.
objectForKey: is a method on NSDictionary.
valueForKey: takes a key to a property, while valueAtKeyPath: takes a so-called keypath. A keypath is a period-delimeted path to a specific property, like #"relationship.property".