Как создать слабую ссылку в Objective-C?

У меня есть такая ситуация:

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

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

теперь вот цикл сохранения. Как я могу разбить этот цикл сохранения? (используя слабую ссылку).... в приведенном выше примере. Спасибо

Ответ 1

Я бы поставил под сомнение причину, по которой вам нужно это сделать в первую очередь, но если вы решите, что это лучшая архитектура данных, я бы использовал 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];

Добавление

Я изменил ответ с помощью +[NSValue valueWithPointer:] на +[NSValue valueWithNonretainedObject:], так как в ARC компилятор будет жаловаться (из-за кастинга от типа объекта до const void *). Хотя функционально то же самое, имя typecasting и method имеет больше смысла (и компилятор фактически позволит вам скомпилировать, не прибегая к хакерству).

Ответ 2

То, как я решил эту проблему в прошлом, - использовать подкласс 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]);

Тем не менее, вам следует убедиться, что ваша слабая ссылка не исчезает, пока вы ее используете.

Ответ 3

Вы можете:

  • вручную разбить цикл, удалив объекты
  • используйте CFArrayCreateMutable() и установите обратный вызов сохранения и освобождения на NULL:

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

Еще лучше, сделайте шаг назад и подумайте о том, как вы можете добиться того, чего хотите по-другому. При правильном дизайне эта проблема может и не возникнуть.

Ответ 4

В iPhone нет понятия слабой ссылки. В ваших случаях я считаю, что это вызовет проблему с высвобождением любого из них.

Обычно для 2 классов я буду делать что-то вроде этого:

Пусть один класс владеет другим, сохраняя его, а другой просто назначает. Некоторые примеры кода могут уточнить его

класс A

@interface A {

}

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

класс B

@interface B {

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

Ответ 5

В среде iPhone без сбора мусора слабая ссылка более или менее определяется как ссылка, где объект не сохраняется. Имея это в виду (фактически даже без этого), вы не можете контролировать, создает ли NSMutableArray слабую ссылку или нет. В среде GC у вас все еще есть цикл, но это не имеет значения, поскольку, когда оба объекта недоступны, они оба уйдут.

Единственное, что вы можете сделать, это вручную разбить цикл. Вы делаете это, удаляя один из массивов из другого.