![](/img/trans.png)
[英]How to get notified when a zeroing weak reference becomes nil on Objective-C under ARC?
[英]How to test if an Objective-C Object can be used with weak reference under ARC?
Apple 提到了兩種方法supportsWeakPointers
,它們記錄在 ARC 的發行說明中,但在實際運行時和框架中從未提及。 還觀察到這種方法實際上在實踐中被忽略。 另一種方法是allowsWeakReference
,它沒有在任何地方記錄,而是在NSObject.h
聲明如下。
- (BOOL)allowsWeakReference NS_UNAVAILABLE;
- (BOOL)retainWeakReference NS_UNAVAILABLE;
在運行時嘗試調用allowsWeakReference
會導致程序崩潰並顯示以下堆棧跟蹤
objc[17337]: Do not call -_isDeallocating.
#0 0x00007fff9900f768 in _objc_trap ()
#1 0x00007fff9900f8aa in _objc_fatal ()
#2 0x00007fff9901bd90 in _objc_rootIsDeallocating ()
#3 0x00007fff97e92ce9 in -[NSObject _isDeallocating] ()
#4 0x00007fff97b5fad5 in -[NSObject(NSObject) allowsWeakReference] ()
#5 0x00007fff97dfe021 in -[NSObject performSelector:] ()
...
...
#11 0x00007fff97a5fd32 in __-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_1 ()
#12 0x00007fff97dafaaa in _CFXNotificationPost ()
#13 0x00007fff97a4bfe7 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#14 0x00007fff8fa0460f in -[NSApplication _postDidFinishNotification] ()
#15 0x00007fff8fa04375 in -[NSApplication _sendFinishLaunchingNotification] ()
#16 0x00007fff8fa0303c in -[NSApplication(NSAppleEventHandling) _handleAEOpenEvent:] ()
#17 0x00007fff8fa02d9d in -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] ()
#18 0x00007fff97df9591 in -[NSObject performSelector:withObject:withObject:] ()
#19 0x00007fff97a827eb in __-[NSAppleEventManager setEventHandler:andSelector:forEventClass:andEventID:]_block_invoke_1 ()
#20 0x00007fff97a81772 in -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] ()
#21 0x00007fff97a81600 in _NSAppleEventManagerGenericHandler ()
#22 0x00007fff96623c25 in aeDispatchAppleEvent ()
#23 0x00007fff96623b03 in dispatchEventAndSendReply ()
#24 0x00007fff966239f7 in aeProcessAppleEvent ()
#25 0x00007fff92101af9 in AEProcessAppleEvent ()
#26 0x00007fff8fa001a9 in _DPSNextEvent ()
#27 0x00007fff8f9ff861 in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#28 0x00007fff8f9fc19d in -[NSApplication run] ()
#29 0x00007fff8fc7ab88 in NSApplicationMain ()
那么,如果兩種方法都不能使用,那么如何測試一個對象是否支持對其形成弱引用呢?
最后一起破解這個。 適用於我需要的用途。
@implementation NSObject (MAWeakReference)
static NSSet *weakRefUnavailableClasses = nil;
+ (void)load {
// https://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html
weakRefUnavailableClasses = [NSSet setWithObjects:
// Classes that don't support zeroing-weak references
@"NSATSTypesetter",
@"NSColorSpace",
@"NSFont",
@"NSFontManager",
@"NSFontPanel",
@"NSImage",
@"NSMenuView",
@"NSParagraphStyle",
@"NSSimpleHorizontalTypesetter",
@"NSTableCellView",
@"NSTextView",
@"NSViewController",
@"NSWindow",
@"NSWindowController",
// In addition
@"NSHashTable",
@"NSMapTable",
@"NSPointerArray",
// TODO: need to add all the classes in AV Foundation
nil];
}
- (BOOL)ma_supportsWeakPointers {
if ([self respondsToSelector:@selector(supportsWeakPointers)])
return [[self performSelector:@selector(supportsWeakPointers)] boolValue];
// NOTE: Also test for overriden implementation of allowsWeakReference in NSObject subclass.
// We must use a bit of hackery here because by default NSObject's allowsWeakReference causes
// assertion failure and program crash if it is not called by the runtime
Method defaultMethod = class_getInstanceMethod([NSObject class], @selector(allowsWeakReference));
Method overridenMethod = class_getInstanceMethod([self class], @selector(allowsWeakReference));
if (overridenMethod != defaultMethod)
return [[self performSelector:@selector(allowsWeakReference)] boolValue];
// Make sure we are not one of classes that do not support weak references according to docs
for (NSString *className in weakRefUnavailableClasses)
if ([self isKindOfClass:NSClassFromString(className)])
return NO;
// Finally, all tests pass, by default objects support weak pointers
return YES;
}
@end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.