2011-01-14 7 views
42

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

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

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

+3

Вы почти наверняка не хотите этого делать. Обычно в такой ситуации ваш код должен транслировать 'NSNotification', на который подписываются несколько объектов (делегаты в вашем вопросе). –

+4

Майк, боюсь, я хочу - для контроля и соображений безопасности. Я хочу знать, какие вещи связаны с моим делегатом. – wh1t3cat1k

+1

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

ответ

48

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

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

EDIT Найдено оригинал статьи: http://ofcodeandmen.poltras.com

+3

Как и с предложением использовать промежуточные объекты NSValue для хранения слабых ссылок, я считаю, что это решение не будет хранить истинные слабые refs, которые устанавливаются в nil, если целевой объект освобождается. Это только мое подозрение, хотя, поправьте меня, если я ошибаюсь. Самым безопасным способом может быть определение собственного вспомогательного объекта, обеспечивающего слабое свойство, и сохранение этого вспомогательного объекта в коллекции (массив, словарь, набор), как это предлагается в комментарии к использованию NSArray. –

+0

На самом деле, я добавил ответ об этом на аналогичный вопрос, см. Здесь: http://stackoverflow.com/a/13351665/43615 –

+0

Просто протестирован в iOS 10.Я не верю, что он больше работает, элемент, который добавляется, это строка вроде «iphoneos10.1». Очень странно. – PaulRBerg

12

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

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

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

+0

Несмотря на то, что автор не искал ответа, мне нужен был кто-то, чтобы его выложить, и у меня есть некоторые восклицательные знаки, чтобы убедиться, что я слушаю ... :) –

+10

Однако здесь * есть ситуации, когда коллекция неиспользуемых объектов полезно. – matt

+1

@matt - Для некоторых и редких случаев у вас есть 'NSHashMap' в Mac OS X или вы можете спуститься до' CFDictionary' на iOS и Mac OS X. – PeyloW

17

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

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

+25

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

+2

@ Ваш комментарий требует большей видимости. опубликуйте его как ответ – codrut

+0

Я отправил свой комментарий в качестве ответа и добавил сексуальную альтернативу, которая использует NSProxy. – Timo

2

Я нашел некоторые фрагменты кода из проекта 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); 
} 
3

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

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); 
} 
11

Я предлагаю не бороться, -рамки и использование NSPointerArray с NSPointerFunctionsWeakMemoryNSPointerFunctionOption, как это:

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 в.

24

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

Johnmph предложил использовать [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 
+0

Святое дерьмо ... УДИВИТЕЛЬНОЕ! Благодаря! NSProxy выглядит забавно. – walkingbrad

0

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

__weak typeof(pointer) weakPointer = pointer; 
0

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

Смежные вопросы