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!
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
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
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).
Je suggérerais de ne pas combattre le framework et d'utiliser NSPointerArray avec le NSPointerFunctionsWeakMemory
NSPointerFunctionOption
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.
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.
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.
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);
}
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);
}
Mot clé: NSHashTable
, recherche dans les documentations.
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
Qu'en est-il de stocker dans le tableau ou le dictionnaire
__weak typeof(pointer) weakPointer = pointer;