web-dev-qa-db-fra.com

Tableau non conservant pour les délégués

Dans un projet Cocoa Touch, j'ai besoin d'une classe spécifique pour avoir non seulement un seul objet délégué, mais plusieurs d'entre eux.

Il semble que je devrais créer un NSArray pour ces délégués; le problème est que NSArray conserverait tous ces délégués, ce qui ne devrait pas (les objets de la convention ne devraient pas conserver leurs délégués).

Devrais-je écrire ma propre classe de tableau pour éviter de conserver ou existe-t-il des méthodes plus simples? Je vous remercie!

43
wh1t3cat1k

J'ai trouvé ce morceau de code il y a quelque temps (je ne me souviens plus à qui l'attribuer).

C'est assez ingénieux, en utilisant une catégorie pour permettre la création d'un tableau mutable qui ne conserve pas/libère en le sauvegardant avec un CFArray avec les rappels appropriés.

@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

EDITTrouvé l'article original: http://ofcodeandmen.poltras.com

47
MarkPowell

Je présente une limitation importante d'une des réponses précédentes, avec une explication et une amélioration.

Johnmph a suggéré d'utiliser [NSValue valueWithNonretainedObject:].

Notez que lorsque vous faites cela, votre référence agit pas comme __weak, mais plutôt comme __unsafe_unretained à l’intérieur de l’objet NSValue. Plus précisément, lorsque vous essayez de récupérer votre référence (en utilisant [myNSValue nonretainedObjectValue]), votre application plantera avec un signal EXC_BAD_ACCESS si l'objet a été désalloué avant!

En d'autres termes, la référence faible n'est pas automatiquement définie sur nil lorsqu'elle se trouve dans l'objet NSValue. Cela m'a pris un tas d'heures à comprendre. J'ai travaillé autour de cela en créant une classe simple avec seulement une propriété ref faible.

Mieux encore, en utilisant NSProxy, nous pouvons traiter l’objet wrapper entièrement comme s’il s’agissait de l’objet contenu lui-même!

// 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
26
Timo

Consultez la documentation de la méthode NSValue valueWithNonretainedObject:

Cette méthode est utile pour empêcher la conservation d’un objet lorsqu’il est ajouté à un objet de collection (comme une instance de NSArray ou NSDictionary).

17
Johnmph

Je suggérerais de ne pas combattre le framework et d'utiliser NSPointerArray avec le NSPointerFunctionsWeakMemoryNSPointerFunctionOption comme ceci:

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.

M'a bien servi dans les scénarios, où je devais concevoir un tableau de délégués, qui référence auto-NULL.

13
leviathan

Vous ne voulez pas faire ça! Cocoa Touch a plusieurs concepts pour l'envoi d'événements, vous devez utiliser le concept approprié pour chaque cas.

  1. Target-action: Pour les contrôles de l'interface utilisateur, tels que les pressions sur les boutons. Un expéditeur, zéro ou plusieurs destinataires.
  2. Délégués: Pour un expéditeur et un destinataire uniquement.
  3. Notification: Pour un expéditeur et zéro ou plus destinataires.
  4. KVO: Plus finement que les notifications.

Ce que vous devriez faire est de regarder comment utiliser la classe NSNotificationCenter. C’est le bon moyen d’envoyer une notification qui a plusieurs destinataires.

12
PeyloW

Celui de NIMBUS serait plus simple:

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);
}
3
flypig

J'ai trouvé des morceaux de code du projet Three20 sur ce sujet, j'espère que cela aide ...

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);
}
2
flypig

Mot clé: NSHashTable, recherche dans les documentations.

1
Klein Mioke

J'ai trouvé une bibliothèque open source nommée XMPPFramewrok

Il y a une solution de délégué multicast dans le projet

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

0
Hailong

Qu'en est-il de stocker dans le tableau ou le dictionnaire

__weak typeof(pointer) weakPointer = pointer;
0
Nicolas Manzini