前兩天發現一個很詭異的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