1

早期警告-コードサンプルが少し長い...

アプリケーション内のどこからでもアクセスできるシングルトンNSMutableArrayがあります。複数のNIBファイルから参照できるようにしたいのですが、オブジェクトNSMutableArrayを介してUI要素にバインドしNSArrayControllerます。最初の作成は問題ではありません。NSMutableArrayNIBがロードされ、すべてが正常に表示されたときに、シングルトンを参照できます。

ただし、オブジェクトを追加または削除してを変更しても、インスタンスNSMutableArrayを更新するためにKVOが開始されるわけではありません。NSArrayController「コントローラーの後ろで変更する」ことはココアランドの立ち入り禁止の部分と見なされていることは理解していますが、プログラムで更新しNSMutableArrayてすべての人NSArrayControllerに通知する方法は他にありません(もちろん機能しない場合を除きます)。 ..)。

説明するために、以下のクラスを簡略化しました。

簡略化されたシングルトンクラスヘッダー:

@interface MyGlobals : NSObject {
    NSMutableArray * globalArray;
}

@property (nonatomic, retain) NSMutableArray * globalArray;

簡略化されたシングルトンメソッド:

static MyGlobals *sharedMyGlobals = nil;

@implementation MyGlobals

@synthesize globalArray;

+(MyGlobals*)sharedDataManager {
    @synchronized(self) {
    if (sharedMyGlobals == nil)
    [[[self alloc] init] autorelease];
}

return sharedMyGlobals;
}

-(id) init {
if(self = [super init]) {
        self.globals = [[NSMutableArray alloc] init];
    }
    return self
}

// ---- allocWithZone, copyWithZone etc clipped from example ----

この簡略化された例では、配列内のオブジェクトのヘッダーとモデルは次のとおりです。

ヘッダーファイル:

@interface MyModel : NSObject {
NSInteger myId;
NSString * myName;
}

@property (readwrite) NSInteger myId;
@property (readwrite, copy) NSString * myName;

-(id)initWithObjectId:(NSInteger)newId objectName:(NSString *)newName;

@end

メソッドファイル:

@implementation MyModel

@synthesize myId;
@synthesize myName;

-(id)init {

[super init];

myName  = @"New Object Name";
myId    = 0;

return self;
}

@end

NSArrayControllerここで、適切なインスタンスを持つ2つのNIBファイルを想像してください。myArrayControllerInNibOneそれらをとと呼びますmyArrayControllerInNib2initNIBコントローラーの各アレイコントローラーは、アレイのコンテンツを設定します。

// In NIB one init
[myArrayControllerInNibOne setContent: [[MyGlobals sharedMyGlobals].globalArray];

// In NIB two init
[myArrayControllerInNibTwo setContent: [[MyGlobals sharedMyGlobals].globalArray];

各NIBNSArrayControllerが共有配列へのバインドを正しく初期化すると、期待どおりにUIに配列の内容が表示されます。外部イベントに基づいてコンテンツが変更されたときにグローバル配列を更新する別のバックグラウンドスレッドがあります。このバックグラウンドスレッドでオブジェクトを追加する必要がある場合は、次のようにオブジェクトを配列に追加するだけです。

[[[MyGlobals sharedMyGlobals].globalArray] addObject:theNewObject];

これは物事がバラバラになるところです。共有インスタンスにキー値がないため、グローバル配列でwillChangeValueForKeyとを呼び出すことができません(これをシングルトンクラスに追加する必要がありますか?)didChangeValueForKey

NSNotification起動してNIBコントローラーでキャッチし、 ;を実行することができ[myArrayControllerInNibOne rearrangeObjects]ます。または、コンテンツnilをアレイに設定して再割り当てしますが、どちらもハックのようです。さらに、グローバル配列に設定してNSArrayControllerからnilグローバル配列に戻すと、コンテンツがクリアされて再入力されるときにUI内で視覚的なフラッシュが発生します。

に直接追加できNSArrayController、配列が更​​新されることはわかっていますが、a)他のNSArrayControllerインスタンスがどのように更新されるか、b)バックグラウンドスレッドクラスをNIBインスタンスに明示的に結び付けたくない(または私がしなければならない必要があります)。

正しいアプローチは、バックグラウンドスレッドでKVO通知を何らかのaddObject方法で起動するか、グローバル配列に格納されているオブジェクトに何かを追加することだと思います。しかし、私は途方に暮れています。

注意点として、私はCoreDataを使用していません。

どんな助けや援助も大歓迎です。

4

1 に答える 1

0

早期警告-少し長く答えてください…</p>

ドメインをモデル化するオブジェクトを使用します。シングルトンやグローバルは必要ありません。通常のクラスの通常のインスタンスが必要です。グローバル配列に格納しているオブジェクトは何ですか?モデルのその部分を表すクラスを作成します。

NSMutableArrayをストレージとして使用する場合は、クラスの内部にあり、外部オブジェクトには表示されないようにする必要があります。たとえば、動物園をモデル化している場合は、実行しないでください

[[[MyGlobals sharedMyGlobals].globalArray] addObject:tomTheZebra];

する

[doc addAnimal:tomTheZebra];

可変配列を監視しようとしないでください。オブジェクトのto-manyプロパティを監視する必要があります。例えば。それ以外の

[[[MyGlobals sharedMyGlobals].globalArray] addObserver:_controller]

あなたが欲しい

[doc addObserver:_controller forKeyPath:@"animals" options:0 context:nil];

ここで、docはto-manyプロパティ'anaimals'に対してkvoに準拠しています。

doc kvoに準拠させるには、これらのメソッドを実装する必要があります(注-これらすべては必要ありません。一部はオプションですが、パフォーマンスが向上します)

- (NSArray *)animals;
- (NSUInteger)countOfAnimals;
- (id)objectInAnimalsAtIndex:(NSUInteger)i; 
- (id)AnimalsAtIndexes:(NSIndexSet *)ix;
- (void)insertObject:(id)val inAnimalsAtIndex:(NSUInteger)i;
- (void)insertAnimals:atIndexes:(NSIndexSet *)ix;
- (void)removeObjectFromAnimalsAtIndex:(NSUInteger)i;
- (void)removeAnimalsAtIndexes:(NSIndexSet *)ix;
- (void)replaceObjectInAnimalsAtIndex:(NSUInteger)i withObject:(id)val;
- (void)replaceAnimalsAtIndexes:(NSIndexSet *)ix withAnimals:(NSArray *)vals;

わかりました、それはかなり怖いように見えますが、私があなたがそれらすべてを必要としないと言ったように、それはそれほど悪くはありません。ここを参照してください。これらのメソッドは、モデルへのインターフェースの一部である必要はありません。追加するだけで済みます。-

- (void)addAnimal:(id)val;
- (void)removeAnimal:(id)val;

そして、kvcアクセサーの観点からそれらを記述します。重要な点は、変更されたときに通知を送信するのは配列ではなく、配列は舞台裏の単なるストレージであり、オブジェクトが追加または削除されたという通知を送信するのはモデルクラスです。

アプリを再構築する必要があるかもしれません。NSArrayControllerを完全に忘れる必要があるかもしれません。

Aaaaaannnnnyyywaaayyy…これを行うと、これは何も得られません

[[[MyGlobals sharedMyGlobals].globalArray] addObject:theNewObject];

またはこれ [doc addAnimal:tomTheZebra];

バックグラウンドスレッドから。あなたはこれを行うことはできません。NSMutableArrayはスレッドセーフではありません。うまくいくと思われる場合は、kvo / binding通知がバックグラウンドでも配信されることです。つまり、バックグラウンドでGUIを更新しようとしますが、これは絶対にできません。アレイを静的にすることは、私が恐れていることでは何の助けにもなりません-あなたはこれのための戦略を考え出さなければなりません..最も簡単な方法はですperformSelectorOnMainThreadが、それを超えて完全に別の質問です。糸通しは難しいです。

そして、その静的配列については、静的な使用をやめるだけで、必要ありません。2つのペン先、2つのウィンドウなどがあるからではありません。モデルを表すインスタンスがあり、そのインスタンスへのポインターをviewControllers、windowControllersなどに渡します。シングルトン/静的変数がないことは、テストに非常に役立ちます。もちろん、これを実行する必要があります。

于 2010-06-25T00:56:23.857 に答える