如何在ARC下得到一个对弱引用()进行归零的数组?我不希望数组保留对象。我希望数组元素在被解除分配时移除它们自己,或者将这些条目设置为零。
同样的,我怎么能用字典做到这一点呢?我不想让字典保留这些价值。同样,我希望字典元素在解除分配值时删除它们自己,或者将值设置为零。(我需要保留键,这是唯一的标识符,至少在相应的值被取消之前是这样。)
这两个问题涉及类似的理由:
但也没有要求对引用进行归零,。
根据文档,NSPointerArray和NSHashMap都不支持ARC下的弱引用。NSValue的nonretainedObjectValue也不能工作,因为它是非零的。
我看到的唯一解决方案是使用(weak)属性创建自己的类似NSValue的包装类,作为这个答案提到,接近尾声。。有什么更好的方法让我看不到吗?
我正在为OSX10.7和iOS 6.0开发。
发布于 2013-01-08 16:28:42
下面是一个零化弱引用包装器类的代码。它与NSArray、NSSet和NSDictionary一起正确工作。
这种解决方案的优点是它与旧操作系统兼容,而且很简单。缺点是在迭代时,您可能需要在使用-nonretainedObjectValue之前验证它是非零的。
这和Cocoanetics回答的第一部分中的包装器是一样的,它使用块来完成相同的事情。
WeakReference.h
@interface WeakReference : NSObject {
__weak id nonretainedObjectValue;
__unsafe_unretained id originalObjectValue;
}
+ (WeakReference *) weakReferenceWithObject:(id) object;
- (id) nonretainedObjectValue;
- (void *) originalObjectValue;
@endWeakReference.m
@implementation WeakReference
- (id) initWithObject:(id) object {
if (self = [super init]) {
nonretainedObjectValue = originalObjectValue = object;
}
return self;
}
+ (WeakReference *) weakReferenceWithObject:(id) object {
return [[self alloc] initWithObject:object];
}
- (id) nonretainedObjectValue { return nonretainedObjectValue; }
- (void *) originalObjectValue { return (__bridge void *) originalObjectValue; }
// To work appropriately with NSSet
- (BOOL) isEqual:(WeakReference *) object {
if (![object isKindOfClass:[WeakReference class]]) return NO;
return object.originalObjectValue == self.originalObjectValue;
}
@end发布于 2013-01-08 06:38:10
对弱引用进行归零需要OSX10.7或iOS 5。
您只能在代码、ivars或块中定义弱变量。AFAIK无法动态(在运行时)创建一个弱变量,因为ARC在编译期间生效。当您运行代码时,它已经为您添加了“保留”和“发布”。
话虽如此,你可能会滥用积木来达到这样的效果。
有一个只返回引用的块。
__weak id weakref = strongref;
[weakrefArray addObject:[^{ return weakref; } copy]];请注意,需要复制块才能将其复制到堆中。
现在您可以随时随地遍历数组,块中的去分配对象将返回零。然后你可以移除那些。
当弱引用为零时,不能让代码自动执行。如果这是您想要的,那么您可以使用关联对象的函数。这些对象与它们关联的对象同时被解除分配。因此,您可以拥有自己的哨兵标记,它通知弱集合有关对象消亡的信息。
您将有一个关联对象来监视dealloc (如果关联是唯一的引用),关联对象将有一个指针来监视集合。然后,在哨兵释放,你调用弱集合,以通知它,被监视的对象已经消失。
下面是我关于关联对象的文章:http://www.cocoanetics.com/2012/06/associated-objects/
以下是我的实现:
---- DTWeakCollection.h
@interface DTWeakCollection : NSObject
- (void)checkInObject:(id)object;
- (NSSet *)allObjects;
@end
---- DTWeakCollection.m
#import "DTWeakCollection.h"
#import "DTWeakCollectionSentry.h"
#import <objc/runtime.h>
static char DTWeakCollectionSentryKey;
@implementation DTWeakCollection
{
NSMutableSet *_entries;
}
- (id)init
{
self = [super init];
if (self)
{
_entries = [NSMutableSet set];
}
return self;
}
- (void)checkInObject:(id)object
{
NSUInteger hash = (NSUInteger)object;
// make weak reference
NSNumber *value = [NSNumber numberWithUnsignedInteger:hash];
[_entries addObject:value];
// make sentry
DTWeakCollectionSentry *sentry = [[DTWeakCollectionSentry alloc] initWithWeakCollection:self forObjectWithHash:hash];
objc_setAssociatedObject(object, &DTWeakCollectionSentryKey, sentry, OBJC_ASSOCIATION_RETAIN);
}
- (void)checkOutObjectWithHash:(NSUInteger)hash
{
NSNumber *value = [NSNumber numberWithUnsignedInteger:hash];
[_entries removeObject:value];
}
- (NSSet *)allObjects
{
NSMutableSet *tmpSet = [NSMutableSet set];
for (NSNumber *oneHash in _entries)
{
// hash is actually a pointer to the object
id object = (__bridge id)(void *)[oneHash unsignedIntegerValue];
[tmpSet addObject:object];
}
return [tmpSet copy];
}
@end
---- DTWeakCollectionSentry.h
#import <Foundation/Foundation.h>
@class DTWeakCollection;
@interface DTWeakCollectionSentry : NSObject
- (id)initWithWeakCollection:(DTWeakCollection *)weakCollection forObjectWithHash:(NSUInteger)hash;
@end
--- DTWeakCollectionSentry.m
#import "DTWeakCollectionSentry.h"
#import "DTWeakCollection.h"
@interface DTWeakCollection (private)
- (void)checkOutObjectWithHash:(NSUInteger)hash;
@end
@implementation DTWeakCollectionSentry
{
__weak DTWeakCollection *_weakCollection;
NSUInteger _hash;
}
- (id)initWithWeakCollection:(DTWeakCollection *)weakCollection forObjectWithHash:(NSUInteger)hash
{
self = [super init];
if (self)
{
_weakCollection = weakCollection;
_hash = hash;
}
return self;
}
- (void)dealloc
{
[_weakCollection checkOutObjectWithHash:_hash];
}
@end这会被这样使用:
NSString *string = @"bla";
@autoreleasepool {
_weakCollection = [[DTWeakCollection alloc] init];
[_weakCollection checkInObject:string];
__object = [NSNumber numberWithInteger:1123333];
[_weakCollection checkInObject:__object];
}如果在自动释放池块中输出allObjects,那么其中有两个对象。外面只有绳子。
我发现,在条目的dealloc中,对象引用已经为零,因此不能使用__weak。相反,我使用对象的内存地址作为散列。当这些仍然在_entries中时,您可以将它们作为实际的对象来处理,并且allObjects返回一个自动释放的强引用数组。
注意:这不是线程安全。处理非主队列/线程上的dealloc,您需要小心同步、访问和变异内部_entries集。
注2:这目前只适用于签入单个弱集合的对象,因为第二个签入将覆盖关联的哨兵。如果您需要多个弱集合,那么哨兵应该有一个这些集合的数组。
注3:为了避免保留周期,我将哨兵对集合的引用改为弱引用。
注4:下面是一个the和helper函数,它为您处理块语法:
typedef id (^WeakReference)(void);
WeakReference MakeWeakReference (id object) {
__weak id weakref = object;
return [^{ return weakref; } copy];
}
id WeakReferenceNonretainedObjectValue (WeakReference ref) {
if (ref == nil)
return nil;
else
return ref ();
}发布于 2013-04-03 19:29:07
NSMapTable应该为你工作。可在iOS 6中获得。
https://stackoverflow.com/questions/14209070
复制相似问题