web-dev-qa-db-ja.com

デリゲート用の非保持配列

Cocoa Touchプロジェクトでは、単一のデリゲートオブジェクトだけでなく、それらの多くを持つ特定のクラスが必要です。

これらのデリゲート用にNSArrayを作成する必要があるようです。問題は、NSArrayがこれらすべてのデリゲートを保持することですが、保持するべきではありません(慣例により、オブジェクトはデリゲートを保持するべきではありません)。

保持を防ぐために独自の配列クラスを作成する必要がありますか、それとももっと単純なメソッドがありますか?ありがとうございました!

43
wh1t3cat1k

私はしばらく前にこのコードを見つけました(誰に起因するのか思い出せません)。

カテゴリを使用して、適切なコールバックを使用して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

48
MarkPowell

説明と改善とともに、以前の回答の1つの重要な制限を提示します。

Johnmphは[NSValue valueWithNonretainedObject:]の使用を提案しました。

これを行うと、参照は__weakのようにではなく、NSValueオブジェクト内では__unsafe_unretainedのように動作することに注意してください。具体的には、([myNSValue nonretainedObjectValue]を使用して)参照を取り戻そうとすると、その時間より前にオブジェクトの割り当てが解除されていると、アプリケーションがEXC_BAD_ACCESSシグナルでクラッシュします。

つまり、NSValueオブジェクト内で、弱参照が自動的にnilに設定されることはありません。これは私が理解するのにたくさんの時間を要しました。弱い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
26
Timo

NSValue valueWithNonretainedObjectメソッドのドキュメントを確認してください:

このメソッドは、オブジェクトがコレクションオブジェクト(NSArrayやNSDictionaryのインスタンスなど)に追加されたときにオブジェクトが保持されないようにするのに役立ちます。

17
Johnmph

フレームワークと戦わずに NSPointerArrayNSPointerFunctionsWeakMemoryNSPointerFunctionOptionとともに次のように使用することをお勧めします。

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の参照であるデリゲート配列を設計する必要があるシナリオで私はうまく機能しました。

13
leviathan

あなたはこれをしたくない! Cocoa Touchには、イベントを送信するためのいくつかの概念があります。それぞれの場合に適切な概念を使用する必要があります。

  1. ターゲットアクション:ボタンの押下などのUIコントロール用。 1つの送信者、0個以上の受信者。
  2. デリゲート:one送信者およびone受信者のみ。
  3. 通知:one送信者、および以上受信者の場合。
  4. KVO:その通知をよりきめ細かくします。

あなたがすべきことは、NSNotificationCenterクラスの使い方を調べることです。これは、複数の受信者がいる通知を送信する適切な方法です。

12
PeyloW

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

このトピックに関する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);
}
2
flypig

キーワード:NSHashTable、ドキュメントを検索します。

2
Klein Mioke

XMPPFramewrok という名前のオープンソースライブラリを見つけました

プロジェクトにはマルチキャストデリゲートソリューションがあります

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

0
Hailong

配列や辞書に保存するのはどうですか

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