首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ARC下弱引用的归零集合

ARC下弱引用的归零集合
EN

Stack Overflow用户
提问于 2013-01-08 06:00:31
回答 8查看 11.6K关注 0票数 41

如何在ARC下得到一个对弱引用()进行归零的数组?我不希望数组保留对象。我希望数组元素在被解除分配时移除它们自己,或者将这些条目设置为零。

同样的,我怎么能用字典做到这一点呢?我不想让字典保留这些价值。同样,我希望字典元素在解除分配值时删除它们自己,或者将值设置为零。(我需要保留键,这是唯一的标识符,至少在相应的值被取消之前是这样。)

这两个问题涉及类似的理由:

但也没有要求对引用进行归零,

根据文档,NSPointerArray和NSHashMap都不支持ARC下的弱引用。NSValue的nonretainedObjectValue也不能工作,因为它是非零的。

我看到的唯一解决方案是使用(weak)属性创建自己的类似NSValue的包装类,作为这个答案提到,接近尾声。。有什么更好的方法让我看不到吗?

我正在为OSX10.7和iOS 6.0开发。

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2013-01-08 16:28:42

下面是一个零化弱引用包装器类的代码。它与NSArray、NSSet和NSDictionary一起正确工作。

这种解决方案的优点是它与旧操作系统兼容,而且很简单。缺点是在迭代时,您可能需要在使用-nonretainedObjectValue之前验证它是非零的。

这和Cocoanetics回答的第一部分中的包装器是一样的,它使用块来完成相同的事情。

WeakReference.h

代码语言:javascript
复制
@interface WeakReference : NSObject {
    __weak id nonretainedObjectValue;
    __unsafe_unretained id originalObjectValue;
}

+ (WeakReference *) weakReferenceWithObject:(id) object;

- (id) nonretainedObjectValue;
- (void *) originalObjectValue;

@end

WeakReference.m

代码语言:javascript
复制
@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
票数 17
EN

Stack Overflow用户

发布于 2013-01-08 06:38:10

对弱引用进行归零需要OSX10.7或iOS 5。

您只能在代码、ivars或块中定义弱变量。AFAIK无法动态(在运行时)创建一个弱变量,因为ARC在编译期间生效。当您运行代码时,它已经为您添加了“保留”和“发布”。

话虽如此,你可能会滥用积木来达到这样的效果。

有一个只返回引用的块。

代码语言:javascript
复制
__weak id weakref = strongref;
[weakrefArray addObject:[^{ return weakref; } copy]];

请注意,需要复制块才能将其复制到堆中。

现在您可以随时随地遍历数组,块中的去分配对象将返回零。然后你可以移除那些。

当弱引用为零时,不能让代码自动执行。如果这是您想要的,那么您可以使用关联对象的函数。这些对象与它们关联的对象同时被解除分配。因此,您可以拥有自己的哨兵标记,它通知弱集合有关对象消亡的信息。

您将有一个关联对象来监视dealloc (如果关联是唯一的引用),关联对象将有一个指针来监视集合。然后,在哨兵释放,你调用弱集合,以通知它,被监视的对象已经消失。

下面是我关于关联对象的文章:http://www.cocoanetics.com/2012/06/associated-objects/

以下是我的实现:

代码语言:javascript
复制
---- 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

这会被这样使用:

代码语言:javascript
复制
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函数,它为您处理块语法:

代码语言:javascript
复制
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 ();
}
票数 24
EN

Stack Overflow用户

发布于 2013-04-03 19:29:07

NSMapTable应该为你工作。可在iOS 6中获得。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14209070

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档