I've been using Objective-C for a while, but I've not been following Apple's guidelines very well. Recently I read Cocoa Design Patterns and the Model Object Implementation Guide, and I'm trying to do some very simple things, but do them very well.
Have I missed any major concepts? Please don't mention self = [super init]; that's been covered many times on SO already. Feel free to critique my #pragma marks though!
#import "IRTileset.h"
#import "IRTileTemplate.h"
#interface IRTileset () //No longer lists protocols because of Felixyz
#property (retain) NSMutableArray* tileTemplates; //Added because of TechZen
#end
#pragma mark -
#implementation IRTileset
#pragma mark -
#pragma mark Initialization
- (IRTileset*)init
{
if (![super init])
{
return nil;
}
tileTemplates = [NSMutableArray new];
return self;
}
- (void)dealloc
{
[tileTemplates release];
[uniqueID release]; //Added because of Felixyz (and because OOPS. Gosh.)
[super dealloc]; //Moved from beginning to end because of Abizern
}
#pragma mark -
#pragma mark Copying/Archiving
- (IRTileset*)copyWithZone:(NSZone*)zone
{
IRTileset* copy = [IRTileset new];
[copy setTileTemplates:tileTemplates]; //No longer insertTileTemplates: because of Peter Hosey
[copy setUniqueID:uniqueID];
return copy; //No longer [copy autorelease] because of Jared P
}
- (void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:uniqueID forKey:#"uniqueID"];
[encoder encodeObject:tileTemplates forKey:#"tileTemplates"];
}
- (IRTileset*)initWithCoder:(NSCoder*)decoder
{
[self init];
[self setUniqueID:[decoder decodeObjectForKey:#"uniqueID"]];
[self setTileTemplates:[decoder decodeObjectForKey:#"tileTemplates"]]; //No longer insertTileTemplates: because of Peter Hosey
return self;
}
#pragma mark -
#pragma mark Public Accessors
#synthesize uniqueID;
#synthesize tileTemplates;
- (NSUInteger)countOfTileTemplates
{
return [tileTemplates count];
}
- (void)insertTileTemplates:(NSArray*)someTileTemplates atIndexes:(NSIndexSet*)indexes
{
[tileTemplates insertObjects:someTileTemplates atIndexes:indexes];
}
- (void)removeTileTemplatesAtIndexes:(NSIndexSet*)indexes
{
[tileTemplates removeObjectsAtIndexes:indexes];
}
//These are for later.
#pragma mark -
#pragma mark Private Accessors
#pragma mark -
#pragma mark Other
#end
(Edit: I've made the changes suggested so far and commented which answers discuss them, in case anyone needs to know why.)
Please don't mention self = [super init]…
So, why aren't you doing that?
The same goes for initWithCoder:: You should be using the object returned by [self init], not assuming that it initialized the initial object.
- (void)dealloc
{
[super dealloc];
[tileTemplates release];
}
As Abizern said in his comment, [super dealloc] should come last. Otherwise, you're accessing an instance variable of a deallocated object.
- (IRTileTemplate*)copyWithZone:(NSZone*)zone
The return type here should be id, matching the return type declared by the NSCopying protocol.
{
IRTileset* copy = [IRTileset new];
[copy insertTileTemplates:tileTemplates atIndexes:[NSIndexSet indexSetWithIndex:0]];
[copy setUniqueID:uniqueID];
You're inserting zero or more objects at one index. Create your index set with a range: location = 0, length = the count of the tileTemplates array. Better yet, just assign to the whole property value:
copy.tileTemplates = self.tileTemplates;
Or access the instance variables directly:
copy->tileTemplates = [tileTemplates copy];
(Note that you must do the copy yourself when bypassing property accessors, and that you are copying the array on behalf of the copy.)
return [copy autorelease];
}
copyWithZone: should not return an autoreleased object. According to the memory management rules, the caller of copy or copyWithZone: owns the copy, which means it is the caller's job to release it, not copyWithZone:'s.
#synthesize tileTemplates;
[et al]
You may want to implement the single-object array accessors as well:
- (void) insertObjectInTileTemplates:(IRTileTemplate *)template atIndex:(NSUInteger)idx;
- (void) removeObjectFromTileTemplatesAtIndex:(NSUInteger)idx;
This is optional, of course.
//However, should I list protocols
here, even though they're already
listed in IRTileset.h?
No, you shouldn't. The class extension declared in the implementation file is an extension, so you don't have to care about which protocols the class has been declared to follow.
I would recommend to mark your instance variables' names with an underscore: _tileTemplates. (Purists will tell you to affix rather than prefix the underscore; do that if you're afraid of them.)
Don't use new to instantiate classes. It's not recommended ever, as far as I understand.
[NSMutableArray new]; // :(
[NSMutableArray arrayWithCapacity:20]; // :)
Don't call [super dealloc] before doing your own deallocation! This can cause a crash in certain circumstances.
- (void)dealloc
{
[tileTemplates release];
[super dealloc]; // Do this last
}
I'm not sure what type uniqueID has, but shouldn't it also be released in dealloc?
I would never put my #synthesize directives in the middle of a file (place them immediately below ´#implementation´).
Also, having no clear idea about the role of this class, countOfTileTemplates doesn't sound good to me. Maybe just ´count´ will do, if it's unambiguous that what this class does it to hold tile templates?
It looks pretty good except you've left your properties open to arbitrary manipulation by external objects. Ideally, the data should be manipulated directly only by the model class itself and external objects should have access only via dedicated methods.
For example what if some external code calls this:
myIRTileset.tileTemplates=someArray;
Boom, you've lost all your data.
You should define both the data properties as readonly. Then write accessors internal to the class that will managed their retention within the class implementation. This way the only way for an external object to change the tileTemplates is by calling the - insertTileTemplates:atIndexes: and removeTileTemplatesAtIndexes: methods.
Edit01:
I think I mangled it the first go, so let me try again. You should setup you data model class in the following pattern:
Interface
#interface PrivateTest : NSObject {
#private
//iVar is invisible outside the class, even its subclasses
NSString *privateString;
#public
//iVar is visible and settable to every object.
NSString *publicString;
}
#property(nonatomic, retain) NSString *publicString; //property accessors are visible, settable and getable.
//These methods control logical operations on the private iVar.
- (void) setPrivateToPublic;
- (NSString *) returnPrivateString;
#end
So in use it would look like:
Implementation
#import "PrivateTest.h"
//private class extension category defines
// the propert setters and getters
// internal to the class
#interface PrivateTest ()
#property(nonatomic, retain) NSString *privateString;
#end
#implementation PrivateTest
//normal synthesize directives
#synthesize privateString;
#synthesize publicString;
// Methods that control access to private
- (void) setPrivateToPublic{
//Here we do a contrived validation test
if (self.privateString != nil) {
self.privateString=self.publicString;
}
}
- (NSString *) returnPrivateString{
return self.privateString;
}
#end
You would use it like so:
PrivateTest *pt=[[PrivateTest alloc] init];
// If you try to set private directly as in the next line
// the complier throws and error
//pt.privateString=#"Bob"; ==> "object cannot be set - either readonly property or no setter found"
pt.publicString=#"Steve";
[pt setPrivateToPublic];
NSLog(#"private=%#",[pt returnPrivateString]); //==> "Steve"
Now the class has bullet proof data integrity. Any object in your app can set and get the publicString string property but no external object can set or get the private.
This means you can safely allow access to the instance by any object in your app without worrying that a careless line of code in some minor object or method will trash everything.
two minor nitpicks:
One is the init method, (where stylistically I'm against having 2 different return points but thats just me), however there's nothing stopping super's init from returning a different object than itself or nil, eg a different object of its class or even just another object altogether. For this reason, self = [super init] is generally a good idea, even if it probably won't do much in practice.
Second is in the copyWithZone method, you don't copy the tileTemplates, which could be intentional but is generally a bad idea (unless they're immutable). Copying an object is supposed to have the same effect as allocing a fresh one, eg. retain count of 1, so don't autorelease it. Also, it doesn't look like you do anything with the zone, so you should probably replace it with something like
- (IRTileTemplate*)copyWithZone:(NSZone*)zone {
IRTileset* copy = [[IRTileset allocWithZone:zone] init];
[copy insertTileTemplates:[tileTemplates copyWithZone:zone]
atIndexes:[NSIndexSet indexSetWithIndex:0]];
[copy setUniqueID:uniqueID];
return copy;
}
thats everything I found; with the exception of the retain count of copy (which WILL lead to bugs later on) mostly just stuff that I prefer, you can do it your way if you like it better. Good work
Related
Today I was at interview and was asked a question:
Generate setter and getter by hands for proper declaration using manual reference counting:
#interface SomeClass : NSObject
{
NSMutableArray* _array;
}
#property (copy) NSArray* array;
#end
My answer was:
- (NSArray *)array
{
#syncronized (self)
{
return [_array copy];
}
}
- (void)setArray:(NSArray *)array
{
#synchronized (self)
{
if (_array != array)
{
[_array release];
_array = [array mutableCopy];
[_array retain]
}
}
}
I never worked using MRC so not sure about correctness of an answer. Please help me to correct this code with description!
I am the author of one of the linked topics and I think now I understand MRC enough to write this answer here:
1) You're obviously leaking the copy in the getter (see it also in the comments) - so it should be balanced by corresponding autorelease call.
Also note, that this copy inside your getter is done because of you need to return immutable object, not because of getters for #properties declared with (copy) require you to do so!
2) Your setter should not retain after mutableCopy, since mutableCopy already does +1 for you.
See the following quotes from Advanced Memory Management Programming Guide
Basic Memory Management Rules.
You own any object you create
You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).
And
Ownership Policy Is Implemented Using Retain Counts
The ownership policy is implemented through reference counting—typically called “retain count” after the retain method. Each object has a retain count.
When you create an object, it has a retain count of 1.
3) In my topic's comments #robmayoff shared the link to open source implementation of runtime: reallySetProperty in objc-accessors.mm with the following reasoning behind it:
The nonatomic retain and copy setters unfortunately have an unnecessary race condition. If, on thread 1, the setter releases _count, and on thread 2 the getter accesses _count before thread 1 has set _count = [count retain], thread 2 may access a deallocated object. Always store the new value in _count before releasing the old value. The real accessor in the Objective-C runtime does it correctly. See reallySetProperty in objc-accessors.mm. – rob mayoff
4) You example is also missing dealloc since you were to write it under MRC.
5) [IMO, maybe subjective] Since your setter is creating copies of array argument, you don't need to have this if (_array != array) check since the task of (copy) setter is, I believe, to produce copies of what is passed, so I think this is may be omitted.
Having these points in mind I would write your example like the following:
- (NSArray *)array
{
id array;
#synchronized (self)
{
array = [_array copy];
}
return [array autorelease];
}
- (void)setArray:(NSArray *)array
{
id oldValue;
#synchronized (self)
{
oldValue = _array;
_array = [array mutableCopy];
}
[oldValue release];
}
- (void)dealloc {
[_array release];
[super dealloc];
}
In answer to your question in the comments:
Is it normal and really can be used in the daily practice?
I would say, that it can be used in a daily practice with the following additional considerations:
1) You should move you ivar declaration into a private category #interface SomeClass () be it inside your .m file or a private class extension.
2) You should make your getters/setters nonatomic since atomicity of this property is on your shoulders (you already do synchronized on your own in both setter and getter).
3) See also the setup from linked topic which omits ivar and uses second #property declaration. In your case it would look like this:
// .h
#interface SomeClass : NSObject
#property (nonatomic, strong, readonly) NSArray *array;
#end
// .m or private class extension
#interface SomeClass()
#property (nonatomic, strong) NSMutableArray *array;
#end
#implementation SomeClass
// and here your getters/setters
#end
This setup looks promising though I haven't really tested it for the case like yours.
P.S. Recently I did some research for this back-to-the-past Manual Reference Counting, let me share with you the following links which I found to be the best on this topic:
Advanced Memory Management Programming Guide (this is the MUST)
An In-depth Look At Manual Memory Management In Objective-C (this one too!)
What clang taught us about Objective-C properties
Memory and thread-safe custom property methods
Source code of objc runtime.
Is there any way to delegate to two objects at a time in Objective-C? I know that delegation pattern implies one response at a time and for multiple listeners and broadcasting there is notification center but notification does not return any value.
If I have a heavily network-based iOS project and need to delegate to multiple listeners and required to return values from them, in this scenario what approach should be the best?
In every class the delegate is one, so one delegate is informed about the event. But nothing forbids you to declare a class with a set of delegates.
Or use Observation instead. A class may be observed by multiple classes.
Example
As requested from the OP, since also some code would be useful, here is a way of doing it:
#interface YourClass()
#property (nonatomic, strong, readwrite) NSPointerArray* delegates;
// The user of the class shouldn't even know about this array
// It has to be initialized with the NSPointerFunctionsWeakMemory option so it doesn't retain objects
#end
#implementation YourClass
#synthesize delegates;
... // other methods, make sure to initialize the delegates set with alloc-initWithOptions:NSPointerFunctionsWeakMemory
- (void) addDelegate: (id<YourDelegateProtocol>) delegate
{
[delegates addPointer: delegate];
}
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
{
// Remove the pointer from the array
for(int i=0; i<delegates.count; i++) {
if(delegate == [delegates pointerAtIndex: i]) {
[delegates removePointerAtIndex: i];
break;
}
} // You may want to modify this code to throw an exception if no object is found inside the delegates array
}
#end
This is a very simple version, you can do it in another way. I don't suggest to make public the delegates set, you never know how it could be used, and you can get an inconsistent state, specially with multithreading. Also, when you add/remove a delegate you may need to run additional code, so that's why making the delegates set private.
You may also a lot of other methods like delegatesCount for example.
PS: The code has been edited to be a NSPointerArray instead of a NSMutableSet, because as stated in the comments a delegate should be held with a weak pointer to avoid retain cycles.
In addition to Ramys answer you could use a [NSHashTable weakObjectsHashTable] instead of a
NSMutableSet. This would keep only a weak reference to your delegates and prevents you from running into memory leaks.
You will get the same behavior you already know from standard weak delegates #property (nonatomic, weak) id delegate;
#interface YourClass()
#property (nonatomic, strong) NSHashTable *delegates;
#end
#implementation YourClass
- (instancetype)init
{
self = [super init];
if (self) {
_delegates = [NSHashTable weakObjectsHashTable];
}
return self;
}
- (void) addDelegate: (id<YourDelegateProtocol>) delegate
{
// Additional code
[_delegates addObject: delegate];
}
// calling this method is optional, because the hash table will automatically remove the delegate when it gets released
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
{
// Additional code
[_delegates removeObject: delegate];
}
#end
Robbie Hanson wrote a multicast delegate implementation. Looks like what you need. He talks about it in more detail here, and how it is used in the XMPPFramework. He has some good discussion about one of the main problems which is how to handle the case where the multiple delegates implement a given method who's return value determines the class' behaviour (and the multiple delegates return different values). Relevant bits:
What is a MulticastDelegate?
The xmpp framework needs to support an unlimited number of extensions.
This includes the official extensions that ship with the framework, as
well as any number of extensions or custom code you may want to plug
into the framework. So the traditional delegate pattern simply won't
work. XMPP modules and extensions need to be separated into their own
separate classes, yet each of these classes needs to receive delegate
methods. And the standard NSNotification architecture won't work
either because some of these delegates require a return variable.
(Plus it's really annoying to extract parameters from a notification's
userInfo dictionary.)
So a MulticastDelegate allows you to plug into the framework using the
standard delegate paradigm, but it allows multiple classes to receive
the same delegate notifications. The beauty of this is that you don't
have to put all your xmpp handling code in a single class. You can
separate your handling into multiple classes, or however you see fit.
If you're writing the function that will call the delegates, you can have as many as you want. But if you're using a class (that you can't change) that calls the delegates, then you can't have more delegates than the class supports.
You could, if it worked out for you, have one delegate call another. Set up the first delegate so it will call the second delegate (whose pointer is stored in the first delegate object). This can be simple, with it pre-defined as to which calls are "passed on", or quite complex, using the dynamic call mechanisms of Objective-C.
One delegate can be setting for only one object but it's possible to store delegates in array.
Variant of Ramy Al Zuhouri is good but I want to say that it may be a problem to release delegates from array because NSArray (like NSMutableArray) classes retain all added objects but delegate in most cases is an assign property without retainCount. Retaining the delegate can bring to consequences that class with delegate implementation will have retainCount + 1.
Solution of this is store delegates in NSMutableArray like pointers to delegate methods.
I'm using singletone class with delegate header.
//YourClass.h file
#protocol YourDelegateProtocol <NSObject>
-(void)delegateMethod;
#end
#interface YourClass : NSObject
+(YourClass *)sharedYourClass;
- (void) addDelegate: (id<YourDelegateProtocol>) delegate;
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
#end
//YourClass.m file
#interface YourClass()
#property (nonatomic, retain) NSMutableArray *delegates;
-(void)runAllDelegates;
#end
#implementation YourClass
#synthesize delegates = _delegates;
static YourClass *sharedYourClass = nil;
+(YourClass *)sharedYourClass {
if (!sharedYourClass || sharedYourClass == nil) {
sharedYourClass = [YourClass new];
sharedYourClass.delegates = [NSMutableArray array];
}
return sharedYourClass;
}
-(void)addDelegate: (id<YourDelegateProtocol>) delegate{
NSValue *pointerToDelegate = [NSValue valueWithPointer:delegate];
[_delegates addObject: pointerToDelegate];
}
-(void)removeDelegate: (id<YourDelegateProtocol>) delegate{
NSValue *pointerToDelegate = [NSValue valueWithPointer:delegate];
[_delegates removeObject: pointerToDelegate];
}
-(void)runAllDelegates{
//this method will run all delegates in array
for(NSValue *val in sharedYourClass.delegates){
id<YourDelegateProtocol> delegate = [val pointerValue];
[delegate delegateMethod];
}
}
-(void)dealloc{
sharedYourClass.delegates =nil;
[sharedYourClass release], sharedYourClass =nil;
[super dealloc];
}
#end
//YourClassWithDelegateImplementation.h file
#include "YourClass.h"
#interface YourClassWithDelegateImplementation : NSObject <YourDelegateProtocol>
#end
//YourClassWithDelegateImplementation.m file
#implementation YourClassWithDelegateImplementation
-(id)init{
self = [super init];
if(self){
//...your initialization code
[[YourClass sharedYourClass] addDelegate:self];
}
return self;
}
-(void)delegateMethod{
//implementation of delegate
}
-(void)dealloc{
[[YourClass sharedYourClass] removeDelegate:self];
[super dealloc];
}
#end
If you want to call callbacks for classes B and C from a class A with only one delegate, you could create a delegate wrapper DWrap which has references to the classes B and C. Then class A calls the callbacks on B and C through DWrap.
I've just been reading a short blog post from Craig Hockenberry about ARC and copy. The question I now have is should parameters passed to initializers that are assigned to instance variables always use copy? Or does it depend on the type of the instance variable?
#import "MyObject.h"
#implementation MyObject {
SomeType *_ivar1;
SomeOtherType *_ivar2;
}
-(id)initWithParam1:(SomeType *)param1 andParam2:(SomeOtherType *)param2
{
if ((self == [super init])) {
_ivar1 = [param1 copy]; // Always good
_ivar2 = [param2 copy]; // practice?
}
return self;
}
#end
I think the key to understanding the post is in this statement:
Since I think it’s a bad idea to use accessors during -init the copy semantics defined by the #property are never used and ARC happily retains the reference instead of copying it.
I think that Craig is talking specifically about the following case:
#interface MyObject : NSObject {
SomeType *_ivar1;
}
-(id)initWithParam1:(SomeType *)param1;
#property (copy, nonatomic) SomeType* prop1;
#end
#implementation MyObject
#synthesize prop1 = _ivar1;
-(id)initWithParam1:(SomeType *)param1 {
if ((self == [super init])) {
/*
Craig could have called
self.prop1 = param1;
but he believes that it's a bad idea to call accessors
from the initializer, so he calls copy explicitly.
*/
_ivar1 = [param1 copy];
}
return self;
}
#end
Depends on the type of the variable and intent.
For simple types -- NSString, NSArray, NSNumber, etc... -- you use copy because you generally want the stored type to be immutable. I.e. it doesn't make sense to have a firstName property where something externally can modify it by passing in an instance of NSMutableString.
For more complex classes -- ones that encapsulate both state and functionality -- you generally do not want to copy it exactly because that state may be changing over time. For example, if your app were a streaming video app that had a VideoPlayer instance that played a video encapsulated in a StreamingVideo instance, you wouldn't want to copy the StreamingVideo as its internal state is constantly going to be changing as more data is downloaded (or an error occurs).
I.e. copy is used when you want an immutable snapshot of state and a reference is used when you want object A to be connected to B for purposes of changing/monitoring/querying B's state.
And, yes, you want it to be consistent. If a property is copy and you have a convenience initializer that sets that property, make sure the convenience initializer also copies whatever is set to the property.
As a part of my transition process from C++ to Objective-C, I intensively read book Cocoa and Objective C Up and Running.
In one of the book code examples, there is a line that does not make sense to me with my current level of knowledge:
It is a declaration of class method + (Photo*) photo;.
Could anybody explain me the reason, please, why the author had decided for the method (Photo*) photo; to declare it as a class method instead of instance method?
I have studiet the theory, that the instane method is something like a class member function and that class method is something like static function in C++. But this still does not answer my question.
Here is the declaration code:
#import <Foundation/Foundation.h>
#interface Photo : NSObject{
NSString* caption;
NSString* photographer;
}
+ (Photo*) photo;
- (NSString*) caption;
- (NSString*) photographer;
- (void) setCaption: (NSString*)input;
- (void) setPhotographer: (NSString*)input;
#end
The implementation code follows:
#import "Photo.h"
#implementation Photo
- (id)init
{
self = [super init];
if (self) {
[self setCaption:#"Default Caption"];
[self setPhotographer:#"Default Photographer"];
}
return self;
}
+ (Photo*) photo {
Photo* newPhoto = [[Photo alloc] init];
return [newPhoto autorelease];
}
- (NSString*) caption {
return caption;
}
- (NSString*) photographer {
return photographer;
}
- (void) setCaption:(NSString *)input {
[caption autorelease];
caption = [input retain];
}
- (void) setPhotographer: (NSString *)input {
[photographer autorelease];
photographer = [input retain];
}
- (void)dealloc
{
[self setCaption:nil];
[self setPhotographer:nil];
[super dealloc];
}
#end
The + (Photo*) photo method is a Factory Method that encapsulates the details of creating an object of the Photo class.
A Factory Method enforces
encapsulation, and allows an object to
be requested without inextricable
coupling to the act of creation.
In this particular example the information being hidden by the factory method is memory management, since the client does not need to worry about releasing the returned object.
It is a common practice in Objective-C APIs to provide factory methods in classes that return autoreleased objects of that same classes. These methods must not contain any of the words “alloc”, “new”, “copy”, or “mutableCopy”, which, according to the convention, indicates that the caller doesn't own the returned object, i.e. it doesn't have to be explicitly released.
Related resources:
Memory Management Rules
Meta answer:
One issue; that method should be
declared as returning id and should
return [[[self alloc] init]
autorelease]; (one line or two,
doesn't matter -- just should refer to
the Class directly). As it is, Photo
is gonna be a pain to subclass.
Expanding -- given this:
+ (Photo*) photo {
Photo* newPhoto = [[Photo alloc] init];
return [newPhoto autorelease];
}
If the class were subclassed, this factory method would not work without being overridden to do pretty much the same thing. However, since Objective-C doesn't support co-variance and contra-variance, there would be no way to declare the subclass's implementation of +photo to return an instance of the subclass without also running a significant risk of compiler warnings. Alternatively, you could down-cast the return value to the more specific class, but that is rife with fragility.
Instead, do this:
+ (id) photo {
id newPhoto = [[self alloc] init];
return [newPhoto autorelease];
}
This fixes both issues:
since it uses self, it'll instantiate an instance of whatever class it is implemented on, including subclasses of Photo.
since it returns id, callers can do both of the following without issue:
Photo *p = [Photo photo];
SubclassOfPhoto *s = [SubclassOfPhoto photo];
In this scenario, photo is a convenience method, which returns you an autoreleased instance of the class.
Since the purpose of photo is to give you an instance, it wouldn't make sense to make it an instance method which would require you to already have an instance.
If you're familiar with Factory Methods, the photo method is similar to that.
+photo is like a constructor. You need a way to get an object to send instance methods to, and this gives you an autoreleased one.
It is equivalent to a static method, as you say. In this case (and all cases of [ClassName className] methods) it's basically a factory method. You're asking the class to construct an instance of itself and pass it back. All such methods should return an autoreleased object.
You can safely ignore methods like that if you want - there will usually be an alloc+init equivalent, but it's often more convenient to use the class method, especially if you're creating a throaway object and don't want to retain it.
Finally, you'll sometimes find classes which require you to use the class method, as they'll hide some clever logic wherein an instance of another class is actually returned. You'll sometimes hear these described as 'class clusters'.
Could anybody explain me the reason, please, why the author had decided for the method (Photo*) photo; to declare it as a class method instead of instance method?
It's basically a wrapper of the constructor litany. Note the source:
+ (Photo*) photo {
Photo* newPhoto = [[Photo alloc] init];
return [newPhoto autorelease];
}
Allocate a new Photo, initialize it, mark it autorelease, and return it. Since it creates the object, there is no object yet to operate upon, ergo this needs to be a class method.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?
When creating a new project in Xcode 4, the boilerplate code adds an underscore character when it synthesizes the ivars in the implementation file as:
#synthesize window = _window;
or:
#synthesize managedObjectContext = __managedObjectContext;
Can someone tell me what is being accomplished here? I'm not a complete nube, but this is one aspect of objective-C I don't understand.
Another point of confusion; in the app delegate implementation, after synthesizing the window iVar as above, in the application didFinishLaunchingWithOptions: method the window and viewController ivars are referred to using self:
self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];
but in the dealloc method it's _window, or _viewController
Thanks
This is an artifact of a previous version of the Objective-C runtime.
Originally, #synthesize was used to create accessors methods, but the runtime still required that instance variables had to be instantiated explicitly:
#interface Foo : Bar {
Baz *_qux;
}
#property (retain) Baz *qux;
#end
#implementation Foo
#synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
#end
People would prefix their instance variables to differentiate them from their properties (even though Apple doesn't want you to use underscores, but that's a different matter). You synthesize the property to point at the instance variable. But the point is, _qux is an instance variable and self.qux (or [self qux]) is the message qux sent to object self.
We use the instance variable directly in -dealloc; using the accessor method instead would look like this (though I don't recommend it, for reasons I'll explain shortly):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
This has the effect of releasing qux, as well as zeroing out the reference. But this can have unfortunate side-effects:
You may end up firing some unexpected notifications. Other objects may be observing changes to qux, which are recorded when an accessor method is used to change it.
(Not everyone agrees on this point:) Zeroing out the pointer as the accessor does may hide logic errors in your program. If you are ever accessing an instance variable of an object after the object has been deallocated, you are doing something seriously wrong. Because of Objective-C's nil-messaging semantics, however, you'll never know, having used the accessor to set to nil. Had you released the instance variable directly and not zeroed-out the reference, accessing the deallocated object would have caused a loud EXC_BAD_ACCESS.
Later versions of the runtime added the ability to synthesize instance variables in addition to the accessor methods. With these versions of the runtime, the code above can be written omitting the instance variables:
#interface Foo : Bar
#property (retain) Baz *qux;
#end
#implementation Foo
#synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
#end
This actually synthesizes an instance variable on Foo called _qux, which is accessed by getter and setter messages -qux and -setQux:.
I recommend against this: it's a little messy, but there's one good reason to use the underscore; namely, to protect against accidentally direct ivar access. If you think you can trust yourself to remember whether you're using a raw instance variable or an accessor method, just do it like this instead:
#interface Foo : Bar
#property (retain) Baz *qux;
#end
#implementation Foo
#synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
#end
Then, when you want to access the instance variable directly, just say qux (which translates to self->qux in C syntax for accessing a member from a pointer). When you want to use accessors methods (which will notify observers, and do other interesting things, and make things safer and easier with respect to memory management), use self.qux ([self qux]) and self.qux = blah; ([self setQux:blah]).
The sad thing here is that Apple's sample code and template code sucks. Never use it as a guide to proper Objective-C style, and certainly never use it as a guide to proper software architecture. :)
Here is another reason. Without underscoring instance variables you frequently obtain warning with the parameters self.title = title and self.rating = rating:
#implementation ScaryBugData
#synthesize title;
#synthesize rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // Warning. Local declaration hides instance variable
self.rating = rating; // Warning. Local declaration hides instance variable
}
return self;
}
#end
You avoid warning by underscoring instance variables:
#implementation ScaryBugData
#synthesize title = _title;
#synthesize rating = _rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // No warning
self.rating = rating; // No warning
}
return self;
}
#end
in the application didFinishLaunchingWithOptions: method the window and viewController ivars are referred to using self
No, they're not. Those are references to the properties window and viewController. That's the point of the underscore, to make it clearer when the property is being used (no underscore) and when the ivar is being accessed directly (with underscore).
Yes, Its is just to differentiate the reference of object. That is , if the object is referred directly use it with underscore, otherwise use self to refer the object.