如何在 Objective-C 中创建弱引用?

发布于 2024-09-16 20:23:19 字数 281 浏览 2 评论 0原文

我有这样的情况:

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

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

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

i have a situation like this:

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

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

now here is a retain cycle, How can i break this retain cycle? (using weak reference)....in above example.
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

百合的盛世恋 2024-09-23 20:23:19

我会质疑您首先需要这样做的原因 - 但如果您确实认为这是最好的数据架构,我会使用 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 获取对象code> 实例,你会这样做:

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

附录

我已将答案从使用 +[NSValue valueWithPointer:] 更改为 +[NSValue valueWithNonretainedObject:],因为在 ARC 下,编译器会抱怨(由于从对象类型转换为 const void *)。虽然功能相同,但类型转换和方法名称更有意义(并且编译器实际上允许您进行编译,而无需诉诸黑客手段)。

I would question the reason you need to do this in the first place - but if you do decide it's the best data architecture, I would use NSValue. To store a reference to an object (without retaining it) in a Foundation collection class, you can use +[NSValue valueWithNonretainedObject:]:

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

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

Then to get your object later on from the NSValue instance, you would do this:

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

Addendum

I've changed the answer from using +[NSValue valueWithPointer:] to +[NSValue valueWithNonretainedObject:], since under ARC, the compiler will complain (due to casting from an object type to const void *). While functionally the same, the typecasting and method name makes more sense (and the compiler will actually let you compile without resorting to hackery).

守护在此方 2024-09-23 20:23:19

我过去解决这个问题的方法是使用 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]);

了,但是,由你来确保你的弱引用在你仍在使用它时不会消失。

The way I've solved this problem in the past is to use a subclass of NSProxy to break the cycle. I'll have an object that stores a weak reference to one of the arrays and passes all messages except memory management ones through to it.

     ┌──── 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

Then your code becomes

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]);

It is, however, up to you to make sure your weak reference doesn't vanish while you are still using it.

清欢 2024-09-23 20:23:19

您可以:

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

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

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

You could:

  • manually break the cycle by removing the objects
  • use CFArrayCreateMutable() and set the retain and release callback to NULL:

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

Even better though, take a step back and think about how you can achieve what you want differently. With a proper design this problem might not even occur.

可可 2024-09-23 20:23:19

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

通常,对于 2 个类,我会这样做:

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

A 类

@interface A {

}

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

B 类

@interface B {

}
@property (nonatomic, assign) A *a;
@end

In iPhone, there is no concept of weak reference. In your cases, I believe that it will cause the problem of over releasing on either of them.

Usually, for 2 classes, I will do something like this:

Let one class own another by retaining and the other just use assign. Some sample code may clarify it

class A

@interface A {

}

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

class B

@interface B {

}
@property (nonatomic, assign) A *a;
@end
愁以何悠 2024-09-23 20:23:19

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

您唯一能做的就是手动打破循环。您可以通过从另一个数组中删除一个数组来实现这一点。

In the iPhone environment without garbage collection, a weak reference is more or less defined as a reference where the object is not retained. With that in mind (actually even without that in mind), you have no control over whether NSMutableArray creates a weak reference or not. In the GC environment, you still have the cycle, but it doesn't matter because once both objects unreachable, they'll both go away.

The only thing you can do is to manually break the cycle. You do that by removing one of the arrays from the other.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文