前两天发现一个很诡异的crash bug,log如下:
-[CFNumber release]: message sent to deallocated instance 0x163576e0
log清楚的告诉我们,这是一个野指针。ARC里也有野指针?!只是我们遇到的太少了,所以忽略了这个问题。仔细追查下去,发现是某一个变量名字是new开头引起的。苹果的官方文档很清楚的告诉我们不能这样做:
To allow interoperation with manual retain-release code, ARC imposes a constraint on method naming:
You cannot give an accessor a name that begins with new. This in turn means that you can’t, for example, declare a property whose name begins with new unless you specify a different getter:
// Won't work:
@property NSString *newTitle;
// Works:
@property (getter=theNewTitle) NSString *newTitle;
但是并不是所有的变量都不能用new开头,上面说的很清楚,这个限制是加在method naming的,之所以变量不能以new开头,是因为变量自动生成的getter方法违反了上述规则。所以,如果我们声明的是基本类型,你用new开头命名是没有问题的。
一般情况下,我们不用担心这个问题,因为(不知道从那个版本开始)Xcode7已经很好的帮我们做了这件事情:
但是,坑就坑在Category中的变量并不会报编译错误。****最容易忽略的case就是CoreData。****笔者遇到的问题就是CoreData一个属性用了new开头的命名方式。
解决方案很简单,修改命名方式即可。
但是
****这样的命名方式为什么会产生一个野指针?****
其实换个角度更好理解这个问题,就是我们多调用了一次release。在ARC中,release都是由编译器来处理的,翻翻clang的文档看看能不能找到些帮助。
Semantics of method families
A method’s membership in a method family may imply non-standard semantics for its parameters and return type.
Methods in the alloc, copy, mutableCopy, and new families — that is, methods in all the currently-defined families except init — implicitly return a retained object as if they were annotated with the ns_returns_retained attribute. This can be overridden by annotating the method with either of the ns_returns_autoreleased or ns_returns_not_retained attributes.
Properties also follow same naming rules as methods. This means that those in the alloc, copy, mutableCopy, and new families provide access to retained objects. This can be overridden by annotating the property with ns_returns_not_retained attribute.
Retained return values
A function or method which returns a retainable object pointer type may be marked as returning a retained value, signifying that the caller expects to take ownership of a +1 retain count. This is done by adding the ns_returns_retained attribute to the function or method declaration, like so:
id foo(void) __attribute((ns_returns_retained));
- (id) foo __attribute((ns_returns_retained));
This attribute is part of the type of the function or method.
When returning from such a function or method, ARC retains the value at the point of evaluation of the return statement, before leaving all local scopes.
When receiving a return result from such a function or method, ARC releases the value at the end of the full-expression it is contained within, subject to the usual optimizations for local values.
用StackOverFlow中的回答概括下:
methods that start with new are assumed to return an object that ARC is responsible for managing and releasing
参考内容:
Semantics of method families
Retained return values
StackOverFlow