看起来我应该为这些委托创建一个 NSArray; 问题是 NSArray 会保留所有这些委托,但它不应该这样做(按照惯例,对象不应该保留它们的委托)。
是否应该编写自己的数组类来防止保留或者是否有更简单的方法? 谢谢!
我一段时间前找到了这段代码(无法记得归功于谁)。
它非常巧妙地使用一个类别,通过使用CFArray
和适当的回调来支持创建不进行保留/释放操作的可变数组。
@implementation NSMutableArray (WeakReferences)
+ (id)mutableArrayUsingWeakReferences {
return [self mutableArrayUsingWeakReferencesWithCapacity:0];
}
+ (id)mutableArrayUsingWeakReferencesWithCapacity:(NSUInteger)capacity {
CFArrayCallBacks callbacks = {0, NULL, NULL, CFCopyDescription, CFEqual};
// We create a weak reference array
return (id)(CFArrayCreateMutable(0, capacity, &callbacks));
}
@end
编辑 找到了原始文章:http://ofcodeandmen.poltras.com
CFArrayCreateMutable(...)
,并像使用NSMutableArray
一样使用它(例如[(NSMutableArray *)myCFArray addObject:aDelegate]
或只是[(id)myCFArray addObject:aDelegate]
)。这是因为NSMutableArray
与CFMutableArrayRef
是“无桥接转换”的。更多信息请参见苹果开发者关于无桥接转换的文章。 - Slipp D. Thompson我在此提出了早期答案中一个重要的限制,以及解释和改进方法。
Johnmph建议使用[NSValue valueWithNonretainedObject:]
。
请注意,当您这样做时,您的引用在NSValue对象内部的行为不像 __weak
,而更像 __unsafe_unretained
。 更具体地说,如果对象在那个时间之前已被释放,当您尝试获取回您的引用(使用[myNSValue nonretainedObjectValue])时,您的应用程序将崩溃并显示EXC_BAD_ACCESS信号!
换句话说,在 NSValue
对象内部,弱引用不会自动设置为nil。这让我花费了很多时间来解决。我通过创建一个只有一个弱引用属性的简单类来解决了这个问题。
更美妙的是,通过使用 NSProxy
,我们可以完全将包装器对象视为其所包含的对象本身!
// WeakRef.h
@interface WeakRef : NSProxy
@property (weak) id ref;
- (id)initWithObject:(id)object;
@end
// WeakRef.m
@implementation WeakRef
- (id)initWithObject:(id)object
{
self.ref = object;
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
invocation.target = self.ref;
[invocation invoke];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.ref methodSignatureForSelector:sel];
}
@end
NSProxy
的性能最佳,除了实现 -forwardInvocation:
之外,您还应该实现 - (id)forwardingTargetForSelector:(SEL)aSelector
。 _(我知道,我知道,-forwardingTargetForSelector:
不在 NSProxy
或 NSObject
协议声明中,但 Obj-C 运行时仍然会用于 NSProxy
子类)_。此外,运行时将首先检查 - (BOOL)respondsToSelector:(SEL)aSelector
_(有时还包括 - (BOOL)conformsToProtocol:(Protocol *)aProtocol
)_,因此您需要实现这些方法才能使用 -forwardingTargetForSelector
。但速度差异是值得的! - Slipp D. Thompson查看NSValue valueWithNonretainedObject方法的文档:
当将一个对象添加到集合对象(例如NSArray或NSDictionary的实例)时,此方法非常有用,可以防止该对象被保留。
我建议不要与框架斗争,而是使用NSPointerArray和NSPointerFunctionsWeakMemory
NSPointerFunctionOption
,像这样:
NSPointerArray *weakReferencingArray = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsWeakMemory];
// NSPointerFunctionsWeakMemory - Uses weak read and write barriers
// appropriate for ARC or GC. Using NSPointerFunctionsWeakMemory
// object references will turn to NULL on last release.
在我需要设计一个委托数组并自动将引用设置为NULL的情况下,它在场景中为我服务得很好。
你不应该这么做!Cocoa Touch 提供了多种发送事件的概念,你应该针对每种情况使用适当的概念。
你应该查看如何使用NSNotificationCenter
类来发送通知,这是向多个接收者发送通知的正确方式。
NSHashMap
的少数和罕见情况,或者可以在iOS和Mac OS X上都使用CFDictionary
。 - PeyloWNSMutableArray* NICreateNonRetainingMutableArray(void) {
return (NSMutableArray *)CFArrayCreateMutable(nil, 0, nil);
}
NSMutableDictionary* NICreateNonRetainingMutableDictionary(void) {
return (NSMutableDictionary *)CFDictionaryCreateMutable(nil, 0, nil, nil);
}
NSMutableSet* NICreateNonRetainingMutableSet(void) {
return (NSMutableSet *)CFSetCreateMutable(nil, 0, nil);
}
关键词:NSHashTable
,在文档中进行搜索。
我在Three20项目中找到了一些关于这个主题的代码片段,希望这能帮到你...
NSMutableArray* TTCreateNonRetainingArray() {
CFArrayCallBacks callbacks = kCFTypeArrayCallBacks;
callbacks.retain = TTRetainNoOp;
callbacks.release = TTReleaseNoOp;
return (NSMutableArray*)CFArrayCreateMutable(nil, 0, &callbacks);
}
NSMutableDictionary* TTCreateNonRetainingDictionary() {
CFDictionaryKeyCallBacks keyCallbacks = kCFTypeDictionaryKeyCallBacks;
CFDictionaryValueCallBacks callbacks = kCFTypeDictionaryValueCallBacks;
callbacks.retain = TTRetainNoOp;
callbacks.release = TTReleaseNoOp;
return (NSMutableDictionary*)CFDictionaryCreateMutable(nil, 0, &keyCallbacks, &callbacks);
}
将其存储在数组或字典中如何?
__weak typeof(pointer) weakPointer = pointer;
我发现了一个名为XMPPFramewrok的开源库。
该项目中有一个多播委托解决方案。
https://github.com/robbiehanson/XMPPFramework/wiki/MulticastDelegate
NSNotification
,让多个对象(问题中的代理对象)进行订阅。 - Mike Abdullah