Не сохраняющий массив для делегатов - PullRequest
43 голосов
/ 14 января 2011

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

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

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

Ответы [ 10 ]

48 голосов
/ 14 января 2011

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

Это довольно изобретательно, использовать Категорию, чтобы разрешить создание изменяемого массива, который не сохраняет / освобождает, поддерживая его 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

26 голосов
/ 06 августа 2013

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

Джонф предложил использовать [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
17 голосов
/ 02 мая 2011

Проверьте документацию метода NSValue valueWithNonretainedObject:

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

13 голосов
/ 06 июня 2013

Я бы посоветовал не бороться с фреймворком и использовать 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.

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

12 голосов
/ 14 января 2011

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

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

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

3 голосов
/ 18 марта 2012

Это из 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);
}
2 голосов
/ 18 марта 2012

Я нашел несколько фрагментов кода из проекта 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);
}
1 голос
/ 13 апреля 2017

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

0 голосов
/ 19 февраля 2014

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

__weak typeof(pointer) weakPointer = pointer;
0 голосов
/ 05 октября 2012

Я нашел библиотеку с открытым исходным кодом с именем XMPPFramewrok

В проекте есть решение для многоадресного делегата

https://github.com/robbiehanson/XMPPFramework/wiki/MulticastDelegate

...