objective-c - 如何测试 Objective-C 对象是否可以在 ARC 下使用弱引用?

标签 objective-c cocoa automatic-ref-counting weak-references

Apple 提到了两种方法 supportsWeakPointers这记录在 ARC 的发行说明中,但在实际运行时和框架中从未提及。还观察到这个 method is in fact ignored in practice.另一种方法是 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

关于objective-c - 如何测试 Objective-C 对象是否可以在 ARC 下使用弱引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9257267/

相关文章:

objective-c - 使用 ARC 从导航 Controller 弹出时保留 View Controller

ios - 将保留对象分配给__unsafe_unretained变量,但是为什么它不崩溃?

ios - 如果我将自动释放的对象桥接到 Core Foundation,我必须使用 __bridge 或 __bridge_retained 吗?

iphone - 如何观察单元格附件类型 UITableViewCellAccessoryCheckmark 是否被选中?

ios - Objective-C二次/多项式回归(Excel中的线性函数)

objective-c - NSTextField 无法识别的选择器

iphone - 两幅图像相交透明度

ios - Xcode - 单元测试 : Test session exited(-1) without checking in

objective-c - 两个数字相加计算器

没有返回类型的 Objective-c 方法