Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 弧下零化弱参考的集合_Objective C_Cocoa Touch_Cocoa_Automatic Ref Counting_Weak References - Fatal编程技术网

Objective c 弧下零化弱参考的集合

Objective c 弧下零化弱参考的集合,objective-c,cocoa-touch,cocoa,automatic-ref-counting,weak-references,Objective C,Cocoa Touch,Cocoa,Automatic Ref Counting,Weak References,如何在ARC下获得一个归零弱引用数组?我不希望数组保留对象。我希望数组元素在释放时删除它们自己,或者将这些条目设置为nil 同样地,我怎样才能用字典做到这一点?我不希望字典保留这些值。同样,我希望dictionary元素在释放值时删除它们自己,或者将值设置为nil。(我需要保留作为唯一标识符的键,至少在释放相应的值之前是这样。) 这两个问题涉及相似的理由: 但这两种方法都没有要求对引用进行归零 根据文档,NSPointerArray和NSHashMap都不支持ARC下的弱引用。NSVal

如何在ARC下获得一个归零弱引用数组?我不希望数组保留对象。我希望数组元素在释放时删除它们自己,或者将这些条目设置为nil

同样地,我怎样才能用字典做到这一点?我不希望字典保留这些值。同样,我希望dictionary元素在释放值时删除它们自己,或者将值设置为nil。(我需要保留作为唯一标识符的键,至少在释放相应的值之前是这样。)

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

但这两种方法都没有要求对引用进行归零

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

我看到的唯一解决方案是使用
(弱)
属性创建自己的类似NSValue的包装类,如下所示。有没有更好的办法让我看不见


我正在为OS X 10.7和iOS 6.0开发。

将弱引用归零需要OS X 10.7或iOS 5

只能在代码、IVAR或块中定义弱变量。AFAIK无法动态(在运行时)创建弱变量,因为ARC在编译时生效。当您运行代码时,它已经为您添加了保留和释放

已经说过,您可能会滥用块来实现这样的效果

有一个只返回引用的块

__weak id weakref = strongref;
[weakrefArray addObject:[^{ return weakref; } copy]];
请注意,您需要复制块以将其复制到堆中

现在,您可以随时遍历数组,块中解除锁定的对象将返回nil。然后您可以删除这些

当弱引用为零时,不能自动执行代码。如果这是您想要的,那么您可以利用关联对象的功能。这些对象与它们关联的对象同时被解除分配。所以你可以有你自己的哨兵标签,通知弱小的收集对象死亡

您将有一个关联的对象来监视dealloc(如果关联是唯一的引用),并且关联的对象将有一个指向监视集合的指针。然后在sentry dealloc中调用弱集合,通知它监视的对象已消失

以下是我对关联对象的写入:

以下是我的实现:

---- 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
如果在自动释放池块内输出AllObject,则其中有两个对象。外面你只有绳子

我发现在条目的dealloc中,对象引用已经是nil,因此不能使用uu弱。相反,我使用对象的内存地址作为散列。当这些仍然在_条目中时,您可以将它们视为实际对象,AllObject返回一个自动释放的强引用数组

注意:这不是线程安全的。要处理非主队列/线程上的dealloc,您需要小心同步访问和修改内部_项集

注意2:这目前仅适用于签入单个弱集合的对象,因为第二次签入将覆盖关联的sentry。如果您需要多个弱集合,那么哨兵应该拥有这些集合的数组

注3:我将哨兵对集合的引用也更改为“弱”,以避免保留循环

注4:以下是typedef和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-01-08 10:00:19.171 X[6515:c07] deallocing
2013-01-08 10:00:19.172 X[6515:c07] 0x0
编辑:我根据这个想法从头开始创建了一个。这是可行的,但它的丑陋有几个原因:

我使用了一个添加@properties的键、下一个映射桶和对拥有该对象的集合的引用

一旦将对象置零,它将从集合中消失

但是,要使地图具有动态容量,它需要接收更新的元素数量,以计算负载系数,并在需要时扩展容量。也就是说,除非您希望在每次添加元素时执行迭代整个数组的Θ(n)更新。我是通过回调我要添加到集合中的示例对象的dealloc方法来实现这一点的。我可以编辑原始对象(为了简洁起见我这样做了),或者从超类继承,或者旋转dealloc。无论如何,丑陋

但是,如果您不介意使用固定容量的集合,则不需要回调。集合使用并假设散列函数的分布均匀,性能将为Θ(1+n/m),即n=元素,m=容量。但是(更多但是)为了避免破坏链接,您需要添加一个前一个链接作为category@property,并将其链接到元素dealloc中的下一个元素。一旦我们接触到dealloc,就可以通知集合元素正在被删除(这就是现在正在做的事情)


最后,请注意,项目中的测试是最小的,我可能忽略了一些东西。

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

此解决方案的优点是它与较旧的操作系统兼容,而且非常简单。缺点是迭代时,在使用它之前,可能需要验证
-nonretainedObjectValue
是否为非nil

这与协同学答案第一部分中的包装器的想法相同,它使用块来完成相同的事情

WeakReference.h

@interface WeakReference : NSObject {
    __weak id nonretainedObjectValue;
    __unsafe_unretained id originalObjectValue;
}

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

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

@end
WeakReference.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

我只是创建了NSMutableDictionary和NSMutableSet的非线程安全弱引用版本。代码如下:

对于NSMutableArray,事情更加复杂,因为它不能包含
nil
,并且一个对象可能会多次添加到数组中。但这是可行的
@interface WeakReference : NSObject {
    __weak id nonretainedObjectValue;
    __unsafe_unretained id originalObjectValue;
}

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

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

@end
@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
@interface WeakReferenceObj : NSObject
@property (nonatomic, weak) id weakRef;
@end

@implementation WeakReferenceObj
+ (id)weakReferenceWithObj:(id)obj{
    WeakReferenceObj *weakObj = [[WeakReferenceObj alloc] init];
    weakObj.weakRef = obj;
    return weakObj;
}
@end

@implementation NSMutableSet(WeakReferenceObj)
- (void)removeDeallocRef{
    NSMutableSet *deallocSet = nil;
    for (WeakReferenceObj *weakRefObj in self) {
        if (!weakRefObj.weakRef) {
            if (!deallocSet) {
                deallocSet = [NSMutableSet set];
            }
            [deallocSet addObject:weakRefObj];
        }
    }
    if (deallocSet) {
        [self minusSet:deallocSet];
    }
}

- (void)addWeakReference:(id)obj{
    [self removeDeallocRef];
    [self addObject:[WeakReferenceObj weakReferenceWithObj:obj]];
}
@end
- (void)didReceiveMemoryWarning{
    [yourWeakReferenceSet removeDeallocRef];
}