10

我有这样的情况:

NSMutableArray * A = [[NSMutableArray alloc]initwithObjects:@"one",nil];
NSMutableArray * B = [[NSMutableArray alloc]initwithObjects:@"two",nil];

[A addObject:B];
[B addObject:A];

现在这是一个保留周期,我怎样才能打破这个保留周期?(使用弱引用)....在上面的例子中。谢谢

4

5 回答 5

12

我会质疑你首先需要这样做的原因 - 但如果你确实认为它是最好的数据架构,我会使用NSValue. 要在 Foundation 集合类中存储对对象的引用(不保留它),您可以使用+[NSValue valueWithNonretainedObject:]

NSMutableArray *a = [[NSMutableArray alloc] initwithObjects:@"one", nil];
NSMutableArray *b = [[NSMutableArray alloc] initwithObjects:@"two", nil];

[a addObject:b];
[b addObject:[NSValue valueWithNonretainedObject:a]];

然后要稍后从NSValue实例中获取您的对象,您可以这样做:

NSMutableArray *c = (NSMutableArray *) [[b objectAtIndex:index] nonretainedObjectValue];

附录

我已将答案从 using 更改+[NSValue valueWithPointer:]+[NSValue valueWithNonretainedObject:],因为在 ARC 下,编译器会抱怨(由于从对象类型转换为const void *)。虽然功能相同,但类型转换和方法名称更有意义(编译器实际上会让您在不求助于骇客的情况下进行编译)。

于 2010-09-01T14:08:55.243 回答
8

我过去解决这个问题的方法是使用 NSProxy 的子类来打破循环。我将有一个对象存储对其中一个数组的弱引用,并将除内存管理消息之外的所有消息传递给它。

     ┌──── NSArray A <────┐
     │                    │
     │                    │
     v        weak        │
ACWeakProxy ┈ ┈ ┈ ┈ ┈ > NSArray B

@interface ACWeakProxy : NSProxy {
    id _object;
}

@property(assign) id object;

- (id)initWithObject:(id)object;

@end

@implementation ACWeakProxy

@synthesize object = _object;

- (id)initWithObject:(id)object {
    // no init method in superclass
    _object = object;
    return self;
}

- (BOOL)isKindOfClass:(Class)aClass {
    return [super isKindOfClass:aClass] || [_object isKindOfClass:aClass];
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation setTarget:_object];
    [invocation invoke];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [_object methodSignatureForSelector:sel];
}

@end

然后你的代码变成

NSMutableArray * A = [[NSMutableArray alloc] initwithObjects:@"one", nil];
NSMutableArray * B = [[NSMutableArray alloc] initwithObjects:@"two", nil];

[A addObject:B];
ACWeakProxy * proxy = [[ACWeakProxy alloc] initWithObject:A];
[B addObject:proxy];
[proxy release];

// will print "two"
NSLog(@"%@", [[[B objectAtIndex:1] objectAtIndex:1] objectAtIndex:0]);

但是,您需要确保您的弱引用在您仍在使用时不会消失。

于 2010-09-01T13:54:55.290 回答
7

你可以:

  • 通过移除对象手动打破循环
  • 使用CFArrayCreateMutable()并将保留和释放回调设置为NULL

    CFArrayCallBacks acb = { 0, NULL, NULL, CFCopyDescription, CFEqual };
    NSMutableArray *noRetain = (NSMutableArray *)CFArrayCreateMutable(NULL, 0, &acb);
    

更好的是,退后一步,想想如何以不同的方式实现你想要的。如果设计得当,这个问题甚至可能不会发生。

于 2010-09-01T13:33:00.553 回答
0

在 iPhone 中,没有弱引用的概念。在您的情况下,我相信这会导致其中任何一个过度释放的问题。

通常,对于 2 节课,我会这样做:

让一个类通过保留拥有另一个类,而另一个只使用分配。一些示例代码可能会澄清它

A级

@interface A {

}

@property (nonatomic, retain) B *b;
@end

B类

@interface B {

}
@property (nonatomic, assign) A *a;
@end
于 2010-09-01T13:31:33.737 回答
0

在没有垃圾回收的 iPhone 环境中,弱引用或多或少被定义为不保留对象的引用。考虑到这一点(实际上即使没有考虑到这一点),您无法控制 NSMutableArray 是否创建弱引用。在 GC 环境中,您仍然有循环,但这没关系,因为一旦两个对象都无法访问,它们都会消失。

您唯一能做的就是手动中断循环。您可以通过从另一个阵列中删除其中一个阵列来做到这一点。

于 2010-09-01T13:57:20.753 回答