iOS -- initWith methods under arc
In the old days, we were trained to write init methods like this:
Foo.h:
-(id) initWithInteger: (NSInteger) someNumber;
Foo.m:
-(id) initWith开发者_StackOverflow社区Integer: (NSInteger) someNumber {
if ((self = [super init])) {
doSomeStuff;
}
return self;
}
But those id casts are now no-nos. So how should these methods now look?
EDIT: This is for a library. So there is no telling what the calling code might look like.
Why do you say returning id
is a no-no? The ARC specification says
init
methods must be instance methods and must return an Objective-C pointer type. Additionally, a program is ill-formed if it declares or contains a call to an init method whose return type is neither id nor a pointer to a super-class or sub-class of the declaring class (if the method was declared on a class) or the static receiver type of the call (if it was declared on a protocol).
Moreover, remember that using ARC
is a per-file decision, i.e. the code compiled with ARC can be used with the code without ARC, and vice versa. In the case of the header file for a library, you should prepare it so that it can be used on both, but preparing it for non-ARC case should suffice.
Here's what I do now:
-(id) initWithInteger: (NSInteger) someNumber {
self = [super init];
if (self) {
doSomeStuff;
}
return self;
}
It makes the warnings go away and it's logically equivalent, although not quite as elegant.
Duh, I feel like a fool now and didn't read the question to understand it. But I found this link that points to something that might help. Specifically it states, in Section 5:
init methods must be instance methods and must return an Objective-C pointer type. Additionally, a program is ill-formed if it declares or contains a call to an init method whose return type is neither id nor a pointer to a super-class or sub-class of the declaring class (if the method was declared on a class) or the static receiver type of the call (if it was declared on a protocol).
Based on that, it looks like you don't have to do anything, which makes sense. Not even Apple is that cruel to its developers. Are you getting compiler errors? I haven't yet jumped to Lion so ARC is not on my radar yet.
In the old days, we were trained to write init methods like this:
Foo.h:
-(id) initWithInteger: (NSInteger) someNumber;
Foo.m:
-(id) initWithInteger: (NSInteger) someNumber { if ((self = [super init])) { doSomeStuff; } return self; }
But those id casts are now no-nos. So how should these methods now look?
Those aren't casts. In that context, that simply syntax declares the return type of the method, as the (NSInteger)
part later on declares the type of that argument.
The syntax for declaring a method's return type has not changed under ARC. The code you showed would remain exactly the same.
Casts are expressions, so a cast of the sort prohibited by ARC can only occur in expression context. For example, if you said:
- (id) initWithCFThing:(CFThingRef)thing {
if ((self = [super init])) {
_thing = (NSThing *)thing; //Casts expression of type CFThingRef to object pointer type NSThing *; this is invalid
}
return self;
}
The cast in the assignment expression is invalid, because it casts from a CF object to an Objective-C object pointer (a “retainable object pointer”) with no bridge keyword. The inverse would likewise be invalid:
- (CFThingRef) CFThing {
return _thing; //Implicitly casts expression of object pointer type NSThing *to type CFThingRef; this is invalid
}
Same problem in the other direction: The expression given to the return
statement casts a retainable object pointer to a CF object type with no bridge keyword.
Note where the errors lie. In each case, the error is in an expression: in initWithCFThing:
, it's the explicit cast-expression inside the assignment expression; in the accessor CFThing
, it's the implicit cast of the expression inside the return
statement to the method's return type.
In both cases, as in your case, the prototype of the method is completely valid. (CFThingRef)
and (id)
are still valid, with or without ARC, when you're declaring a return type or argument type for a method. Only as a cast expression is either syntax invalid, because the cast itself is invalid.
Adding a bridge keyword satisfies the compiler in a cast expression, because then you're telling it what you want it to do (bridge-crossing casts with no bridge keyword are invalid because the compiler would have to guess what you mean, and it refuses), but would be invalid in a type declaration because that is not ambiguous. The bridge crossing happens at the cast expression (when there is one), not at an argument passage or return.
精彩评论