Неподдерживающий массив для делегатов

В проекте Cocoa Touch мне нужен определенный класс, чтобы иметь не только один объект-делегат, но и многие из них.

Похоже, я должен создать NSArray для этих делегатов; проблема в том, что NSArray сохранил бы все эти делегаты, чего он не должен (по объектам конвенции не должен сохранять своих делегатов).

Должен ли я писать собственный класс массива для предотвращения сохранения или есть более простые методы? Спасибо!

Ответ 1

Я нашел этот бит кода некоторое время назад (не могу вспомнить, к кому его привязать).

Это довольно интересно, используя категорию, чтобы разрешить создание изменяемого массива, который не сохраняет/освобождает, поддерживая его с помощью CFArray с соответствующими обратными вызовами.

@implementation NSMutableArray (WeakReferences)
    + (id)mutableArrayUsingWeakReferences {
    return [self mutableArrayUsingWeakReferencesWithCapacity:0];
    }

    + (id)mutableArrayUsingWeakReferencesWithCapacity:(NSUInteger)capacity {
    CFArrayCallBacks callbacks = {0, NULL, NULL, CFCopyDescription, CFEqual};
    // We create a weak reference array
    return (id)(CFArrayCreateMutable(0, capacity, &callbacks));
    }
@end

РЕДАКТИРОВАТЬ Найдено оригинал статьи: http://ofcodeandmen.poltras.com

Ответ 2

Я представляю важное ограничение одного из ранних ответов, а также объяснение и улучшение.

Джонмф предложил использовать [NSValue valueWithNonretainedObject:].

Обратите внимание, что когда вы это делаете, ваша ссылка действует не как __weak, а скорее как __unsafe_unretained, находясь внутри объекта NSValue. Более конкретно, когда вы пытаетесь вернуть свою ссылку (используя [myNSValue nonretainedObjectValue]), ваше приложение выйдет из строя с помощью сигнала EXC_BAD_ACCESS, если объект был освобожден до этого времени!

Другими словами, слабая ссылка автоматически не устанавливается на ноль, находясь внутри объекта NSValue. Это заняло у меня несколько часов, чтобы понять. Я работал над этим, создав простой класс со слабым значением ref.

Более красиво, используя NSProxy, мы можем полностью обрабатывать объект-обертку, как если бы это был сам содержащийся объект!

// WeakRef.h
@interface WeakRef : NSProxy

@property (weak) id ref;
- (id)initWithObject:(id)object;

@end


// WeakRef.m
@implementation WeakRef

- (id)initWithObject:(id)object
{
    self.ref = object;
    return self;
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    invocation.target = self.ref;
    [invocation invoke];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    return [self.ref methodSignatureForSelector:sel];
}

@end

Ответ 3

Проверить документацию значения NSValueWithNonretainedObject:

Этот метод полезен для предотвращения сохранения объекта при его добавлении в объект коллекции (например, экземпляр NSArray или NSDictionary).

Ответ 4

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

  • Целевое действие: для элементов управления пользовательского интерфейса, например нажатия кнопок. Один отправитель, ноль или более получателей.
  • Делегаты: только для одного отправителя и одного.
  • Уведомление: для отправителя один и ноль или более.
  • KVO: более мелкозернистые уведомления.

Что вы должны сделать, так это посмотреть, как использовать класс NSNotificationCenter. Это правильный способ отправить уведомление, содержащее несколько приемников.

Ответ 5

Я предлагаю не-бороться-рамки и использовать NSPointerArray с помощью NSPointerFunctionsWeakMemory NSPointerFunctionOption следующим образом:

NSPointerArray *weakReferencingArray = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsWeakMemory];

// NSPointerFunctionsWeakMemory - Uses weak read and write barriers 
// appropriate for ARC or GC. Using NSPointerFunctionsWeakMemory 
// object references will turn to NULL on last release.

Хорошо служил в сценариях, где мне приходилось создавать массив делегатов, которые ссылаются на авто-NULL.

Ответ 6

Это одно из NIMBUS было бы более простым:

NSMutableArray* NICreateNonRetainingMutableArray(void) {
  return (NSMutableArray *)CFArrayCreateMutable(nil, 0, nil);
}

NSMutableDictionary* NICreateNonRetainingMutableDictionary(void) {
  return (NSMutableDictionary *)CFDictionaryCreateMutable(nil, 0, nil, nil);
}

NSMutableSet* NICreateNonRetainingMutableSet(void) {
  return (NSMutableSet *)CFSetCreateMutable(nil, 0, nil);
}

Ответ 7

Я нашел некоторые фрагменты кода из проекта Three20 по этой теме, надеюсь, это поможет...

NSMutableArray* TTCreateNonRetainingArray() {
  CFArrayCallBacks callbacks = kCFTypeArrayCallBacks;
  callbacks.retain = TTRetainNoOp;
  callbacks.release = TTReleaseNoOp;
  return (NSMutableArray*)CFArrayCreateMutable(nil, 0, &callbacks);
}


NSMutableDictionary* TTCreateNonRetainingDictionary() {
  CFDictionaryKeyCallBacks keyCallbacks = kCFTypeDictionaryKeyCallBacks;
  CFDictionaryValueCallBacks callbacks = kCFTypeDictionaryValueCallBacks;
  callbacks.retain = TTRetainNoOp;
  callbacks.release = TTReleaseNoOp;
  return (NSMutableDictionary*)CFDictionaryCreateMutable(nil, 0, &keyCallbacks, &callbacks);
}

Ответ 9

Как насчет сохранения в массиве или словаре

__weak typeof(pointer) weakPointer = pointer;

Ответ 10

Ключевое слово: NSHashTable, поиск в документах.