gpt4 book ai didi

objective-c - NSArrayController 在多个 NIB 中访问单例 NSMutableArray

转载 作者:行者123 更新时间:2023-12-03 17:26:45 24 4
gpt4 key购买 nike

早期警告 - 代码示例有点长...

我有一个单例 NSMutableArray,可以从应用程序中的任何位置访问它。我希望能够引用NSMutableArray来自多个 NIB 文件,但通过 NSArrayController 绑定(bind)到 UI 元素对象。初始创建不是问题。我可以引用单例NSMutableArray当 NIB 被加载并且一切看起来都很好时。

但是,更改 NSMutableArray通过添加或删除对象不会启动 KVO 来更新NSArrayController实例。我意识到“在 Controller 背后进行更改”被认为是 Cocoa-land 的禁忌部分,但我没有看到任何其他方式以编程方式更新 NSMutableArray并让每个NSArrayController收到通知(当然它不起作用......)。

我在下面简化了类(class)来解释。

简化的单例类 header :

@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 ----

在这个简化的示例中,数组中对象的 header 和模型:

头文件:

@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 的 NIB 文件实例。我们称它们为myArrayControllerInNibOnemyArrayControllerInNib2init中的每个阵列 Controller NIB Controller 的设置数组的内容:

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

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

当每个NIB初始化NSArrayController时正确绑定(bind)到共享数组,我可以按照您的预期在 UI 中看到数组内容。我有一个单独的后台线程,当内容根据外部事件发生变化时,它会更新全局数组。当需要在此后台线程中添加对象时,我只需将它们添加到数组中,如下所示:

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

这就是事情崩溃的地方。我无法调用willChangeValueForKeydidChangeValueForKey在全局数组上,因为共享实例没有键值(我应该在单例类中添加它吗?)

我可以发射一个NSNotification并在 NIB Controller 中捕获它,然后执行 [myArrayControllerInNibOne rearrangeObjects] ;或者将内容设置为nil并将内容重新分配给数组 - 但这两者看起来都像是黑客和。此外,设置 NSArrayControllernil然后返回全局数组,当内容被清除并重新填充时,会导致 UI 内出现视觉闪烁。

我知道我可以直接添加到 NSArrayController并且数组得到更新,但我没有看到 a) 其他 NSArrayController 如何实例将被更新,并且 b) 我不想将我的后台线程类显式绑定(bind)到 NIB 实例(我也不应该这样做)。

我认为正确的方法是在addObject周围以某种方式触发KVO通知。在后台线程中,或者向存储在全局数组中的对象添加一些内容。但我却不知所措。

需要注意的是,我没有使用 Core Data。

任何帮助或协助将不胜感激。

最佳答案

预警 - 回答有点长......

使用对您的域进行建模的对象。您不需要单例或全局变量,您需要常规类的常规实例。您的全局数组中存储了哪些对象?创建一个代表模型的该部分的类。

如果您使用 NSMutableArray 作为存储,它应该位于您的类的内部,并且对外部对象不可见。例如,如果您正在建模动物园,请不要这样做

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

做做

[doc addAnimal:tomTheZebra];

不要尝试观察可变数组 - 您想观察对象的多对多属性。例如。而不是

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

你想要

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

其中 doc 对于多对多属性“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;

好吧,这看起来很吓人,但也没那么糟糕,就像我说的,你并不需要它们全部。 See here 。这些方法不需要成为模型接口(interface)的一部分,您只需添加:-

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

并根据 kvc 访问器编写它们。关键点是,数组不是在更改时发送通知的,数组只是幕后的存储,是模型类发送对象已添加或删除的通知。

您可能需要重组您的应用。您可能需要完全忘记 NSArrayController。

Aaaaaannnnnyyywaaayyy…如果你这样做,所有这些都不会给你带来任何好处

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

或者这个[doc addAnimal:tomTheZebra];

来自后台线程。你不能这样做。 NSMutableArray 不是线程安全的。如果它看起来有效,那么最好的情况是 kvo/绑定(bind)通知也在后台传递,这意味着您将尝试在后台更新 GUI,但您绝对不能这样做。恐怕使数组静态没有任何帮助 - 您必须为此想出一个策略..最简单的方法是 performSelectorOnMainThread 但除此之外完全是另一个问题。线程很难。

关于那个静态数组——停止使用静态,你不需要它。不是因为你有 2 个 Nib 、2 个窗口或任何东西。你有一个代表你的模型的实例,并将指向该模型的指针传递给你的 View Controller 、窗口 Controller 等。没有单例/静态变量对测试有很大帮助,当然你应该这样做。

关于objective-c - NSArrayController 在多个 NIB 中访问单例 NSMutableArray,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3113974/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com