I've had various cases where an Objective-C class has a property that needs to be a collection class (NSArray usually). Is there a standard way to implement this? It would be great to be able to just use #synthesize to set this up. I could just declare the property as NSMutableArray and #synthesize that, but that doesn't allow me to enforce what types of objects can be placed into the collection, nor does it prevent the client code from modifying the array. What I typically do is something like this:
#property(nonatomic, readonly) NSArray *widgets;
- (void)addWidget:(Widget*)widget;
- (void)removeWidget:(Widget*)widget;
...
The collection is implemented as an NSMutableArray, with an NSArray containing the current contents passed back to the caller. This seems like a lot of coding for what must be a common scenario. Even more coding needs to be done in order to set up key-value observing.
Am I missing something, or is it really this much to work to set up a collection property?
You can prevent client code from modifying your array by declaring the property as an NSArray, but using an NSMutableArray as the storage mechanism. The #property and #synthesize directives will still work.
There isn't really a good way to ensure type-safety of the objects returned by your array, but Objective-C programmers almost never worry about that. Its just not a common concern. If you really want to ensure that only objects of a certain type go into and come out of your array, you're going to have to write a wrapper class for NSArray to do so.
Related
When I have my own init method with synthesized properties as such:
#property (copy, nonatomic) NSString *bookName;
#property (strong, nonatomic) NSMutableArray *book;
When I want to initialize with my own custom initializer I am shown to write it like this:
-(id) initWithName: (NSString *)name
{
self = [super init]
if (self) {
bookName = [NSString stringWithString: name];
book = [NSMutableArray array];
}
return self;
}
Now I want to clarify something. I know why it uses the stringWithString method, because instead of just passing the address to the passed in string it'll create a new object so that it owns the string itself. Could I not also just write it like so:
self.bookName = name;
Doing this should use the synthesized method and actually create a new object right? Basically both accomplish the same thing. I ask because there are methods else where that show doing it both ways so I just want to make sure there are no other issues that could crop up with using one way or the other. They both appear to do the same thing in different ways (using the synthesized method vs directly modifying the class variable but creating a new object in memory for it).
I'll also point out that this is in an ARC environment.
(Note that I am assuming the above is ARC code; otherwise it is incorrect.)
You should almost always use accessors to access your ivars (even in ARC). However, there is some controversy about whether init should use accessors or directly access its ivars. I have switched sides in this controversy, but it's not an obvious decision IMO.
The primary argument for not allowing init to use accessors is that it is possible that a future (unknown) subclass might create side-effects in the accessor. You generally don't want side effects happening during your init. For instance, you probably don't want to post change notifications when you're setting something to its initial value, and it is possible that your object is in an "undefined state" and would be dangerous to read at this point.
That said, and while this argument did finally sway me, I have never once encountered this situation on numerous projects of various sizes with several teams. I have many times encountered developers failing to retain when setting their ivars in init (as you have done above, and which would crash if it is not ARC). This is why for a long time I recommended using accessors even in init. But in theory it does create a danger, particularly if you are a closed-source framework writer (i.e. Apple). And so, for my own code I now avoid accessors in init. If I were working with a more junior teams on older retain/release code, I would probably still have them use accessors in init. It's just avoided so many crashes in my experience.
It is not controversial that you should avoid calling accessors in dealloc, however. This definitely can lead to bizarre side-effects in the middle of destroying your object.
You are correct, since bookName is declared as copy, assigning self.bookName would make a copy of the string passed in. I am not certain that copying would go through exactly the same code path as the [NSString stringWithString: name], but it would achieve the same purpose of creating a copy of the original string, shielding you from unexpected consequences of users passing in a mutable object and mutating its value behind your back.
Because the declared property is copy then yes, they are doing the same thing.
Many times however, it is a strong and then there would be a difference between the two methods so the first method would be the "correct" way of doing it.
I want to make sure I understand a key concept of properties and instance variable ownership of a class, in this case using NSArray.
Suppose I pass a reference to an NSArray to another class, and set that class's iVar to it. For example:
First Technique
OtherClass.h
#property (nonatomic, retain) NSArray * otherClassArray;
then:
CurrentClass.m
otherclass.otherClassArray=myArray
Now, even though OtherClass is retaining myArray, if CurrentClass changes myArray then otherclass.otherClassArray will also change, correct?
So, is this the better way to do it, or am I mistaken and the above will do what I'd expect from the following anyway:
Second Technique
CurrentClass.m
otherclass.otherClassArray=[NSArray arrayWithArray:myArray]
Now there is a distinct copy being made so any changes to myArray have no effect on otherClassArray, am I right, or are both of these approaches doing the same thing?
UPDATE: Is there any reason why my second technique above should or should not be used vs. using copy with the property? It would seem that either technique results in a new NSArray that my class owns.
This is exactly why it is generally recommended that properties whose classes have mutable subclasses (most notably, NSString and the various collection classes) be declared as copy:
#property (nonatomic, copy) NSArray * otherClassArray;
Then whenever you set the property, OtherClass will get its own version of the array.
Your second technique has the same result as declaring a copy property, yes, but it should be left up to the property's owner whether it wants a copy or not. To put it another way, the principle of encapsulation demands that client code (CurrentClass) not be responsible for knowing that OtherClass needs to have its own version of the object. It's a matter of design and maintainability.
First I have to do
#property (retain) aMember;
Then in implementation file I got to do
#synthesize aMember;
Then in dealloc, I got to do
self.aMember= nil; (or [aMember release])
That's 3 times writing what essentially is the same
Is there a way to speed this up?
I mean I can drag drop a control from a IB and xcode automatically generate those codes why I can't do that for more normal codes?
As someone coming from C# and managed languages for my day job I completely agree with you in questioning this 3 step process. In fact its almost crazy easy to create properties in C# in MS Visual Studio, but I digress.
Even though there are these 3 lines you have to write there is a huge amount of work going on under the covers for your.
Your declaration of the #property tells objective-c some important attributes (atomic, nonatomic, retain, copy, etc) in how to deal with your property when it is set by users of your class. When you think about this, these attributes (without you writing any code) are; helping you create thread safe code, handling references to objects so you don't have to worry about them disappearing on you, or copying values so you have your own copy of an object. The #property is also important since it is declared in your header file (typically). This give other developers an idea of the properties of your class and some small hints as to how objects they pass into those properties will be handled during its lifetime.
The #synthesize is also doing quite a bit of work by creating the getters and setters for that property, that also handle all sorts of memory management for you. You don't need to worry about releasing the old references and correctly referencing the new object. This alone to me is a great feature, especially when you are new to objective-c and it is easy to forget to deal with memory management at every turn. The #synthesize just does it for you and you don't have to write all the get and set code yourself.
The dealloc call is just life in a non-memory managed environment. While it adds additional steps, I appreciate the benefits that explicit memory management allows in a constrained environment such as the phone.
So all 3 steps are required, are different and when you think about it actually do quite a bit of work for you under the covers.
Unfortunately, that's how it is (for now). Apple had recently toyed with allowing Clang to implicitly synthesize your properties, which would have reduced your work to:
#interface Blah : NSObject
#property (retain) Blorg *blorg;
#end
#implementation Blah
- (void)dealloc {
[blorg release];
[super dealloc];
}
#end
When you didn't want an instance variable to be synthesized, you'd just explicitly put #dynamic blorg in your implementation. But this feature was removed due to some unforeseen complications, despite mostly positive reactions from developers.
So, I think it's safe to expect that Apple's still working on this. But for now, you do need to explicitly synthesize.
A few other notes:
If you are using garbage collection, you don't need to implement -dealloc: just make sure to do any last-minute cleanup in -finalize (such as notification unregistration).
You could also avoid the -dealloc bit by wrapping your instance variable in a C++ class which performs memory management during construction and destruction: #property prop_wrapper<Blorg> blorg; would work. Then, when your object is destroyed, ~prop_wrapper() would be called on your object. I've done this, and it works, but I recommend against it, since it doesn't play nice with KVO and KVC.
You could iterate through the properties of an object, and release those that are annotated with copy or retain. Then, in -dealloc, you'd have something like [self releaseProperties]. I've also done this, but I also recommend against it, since it can cause subtle problems which may result in inexplicable crashes if you're not careful.
To actually add a member variable in objective-c you don't need to do any of that.
What you're doing in those 3 steps is:
Declare properties for a member variable. (In your case you are indicating that you want the property setter to 'retain' the object that it sets your member variable to)
Declare the property getters and setters in a default way for your property.
Release the object that your property is retaining.
IF you only wanted to declare a member variable, all you had to do was declare it inside your class:
#interface SomeClassObject : NSObject {
int someMemberVariable;
}
#end
That's 3 times writing what essentially is the same
No it isn't.
#property (retain) aMember;
The above line declares a property so that the compiler knows it is OK to send the messages -aMember and -setAMember: to objects of your class. It also tells the compiler (and developers) that the property is a retain property (i.e. the object you set the property to will be retained), that it is read/write and that it is atomic.
#synthesize aMember;
The above line tells the compiler that it should automatically generate the setter and getter methods for the declared property. You can leave that out but then you have to write your own setter and getter.
[aMember release]; // in dealloc
Is there to tell the runtime that when the object is being deallocated, it no longer needs to hold a reference to that instance variable. This is necessary because, when you use reference counting rather than garbage collection, the runtime does not automatically clean up unwanted objects.
Each of those lines does a different thing. So you are not doing the same thing three times.
I've bene working with Objective-C for a while now, and so far I have never really needed to craft my own classes, properly.
I am a bit confused with the two arguments you can give the #property(a, b) declaration in a header file. When creating outlets to Interface Builder I usually do #property(nonatomic, retain) but I have no idea what this means.
I'm writing a simple class which has a set of properties which will be set from the outside, like [instance setName:#"Bla Bla Bla"]; or I guess like instance.name = #"Bla#" but I would rather the first option.
How would I declare this kind of property on a class?
Thanks in advanced!
Sorry for the n00bish question :-)
The #property parameter gives you a hint on the property behavior:
nonatomic tells you that setting/getting the property value is not atomic (wrt to multiple thread access)
retain tells you the object will be retained by the property (i.e. The receiver will take ownership of the object). The othe options are "copy" (the object is copied using -copy. This is generally the good choice for value objects like NSStrings) and "assign" (the object is just assigned to the property without retaining it. This is generally the good choice for delegates or datasources). These 3 options are only useful for ObjC objects, not simple C type properties.
See http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html for more info.
For your case, you'll likely use:
#property(copy) NSString* name;
Or:
#property(nonatomic, copy) NSString* name;
If you don't need the property setter/getter to be atomic.
Objective-C 2.0 gave us #properties.
They allow for introspection.
They allow for declarative programming.
The #synthesize and #dynamic mechanisms relieve use from having to write repetitive, stock accessors.
Finally, there is the ‘dot’ property syntax, which some love, and some hate.
That isn't what I'm hear to ask. Like any new feature, there is an initially tendency to want to use #property everywhere. So where is property use appropriate?
Clearly in model objects, attributes and relationships are good fodder for properties.
#property(...) NSString *firstName;
#property(...) NSString *lastName;
#property(...) Person *parent;
Even synthesized/computed attributes seem like a good use case for properties.
#property(...) NSString *fullName;
Where else have you used properties? Where have you used them, then later decided it was an inappropriate use of the feature?
Do you use properties for your private object attributes?
Can you think of any examples of things which aren't properties in Cocoa, which at first look, seem like they might want to be properties, but after closer inspection, are actual an example of abuse or property-itis?
My recommendation to people is to use property's wherever possible. If you are working in a framework, the ability to use non-fragile instance variables in the modern runtime is a huge bonus and if you aren't, properties make it clear how your ivars are to be managed (assigned vs retained vs copied). There isn't an inherent performance loss from declaring a property other than the time it takes to write the line of code (I actually use a TextExpander snippet to do this for me) but the potential for preventing bugs is large enough that it becomes a fantastic best-practice. If you do plan to user properties for private ivars, you can do so inside your implementation file via an #interface block. For example
#interface MyObject()
#property(retain) NSArray *myArray;
#end
If I had to think of a reason to avoid them, I'd say don't use it for computed attributes where the computation involved is significant. Properties encourage code like:
if (foobar.weight > 100) {
goober.capacity = foobar.weight;
}
In this example, foobar.weight is called twice. If it's just returning a cached value, no problem. But if it needs to block the thread while it deploys a robot to manually weigh the foobar each time, the above snipped of code would waste two robot deployments when only one is needed.
In such cases, I'd recommend NOT using a property, and also naming the method differently, so that the code would look more like:
int w = [foobar computeWeight];
if (w > 100) {
goober.capacity = w;
}
With a name like computeWeight it is easier to remember that it is a long running operation.
I would avoid using properties if the accessor method does something non-obvious to the object, like setting an unrelated instance variable. Also if the property being returned doesn't really "belong" to the object. For instance, in one of my projects I have a stringValue method that I decided not to make a property for this reason. This is really more a matter of style though.