[英]How to add observer on NSMutableArray?
I have searched a lot but didn't find useful code or tutorial. 我搜索了很多,但没有找到有用的代码或教程。
In my application, I have an mutable array which update in every 60 seconds. 在我的应用程序中,我有一个可变数组,每60秒更新一次。
The objects in array is being displayed by table view in multiple view controllers. 数组中的对象由多个视图控制器中的表视图显示。
I want to reload table view automatically when only when values in array changes or updated. 我只想在数组中的值更改或更新时自动重新加载表视图。
For this, I want to add observer on mutable array ie when values in array changes then it should call a particular method for eg 为此,我想在可变数组上添加观察者,即当数组中的值发生变化时,它应该调用特定的方法,例如
-(void)ArrayUpdatedNotification:(NSMutableArray*)array
{
//Reload table or do something
}
Thanks in advance. 提前致谢。
You can abstract the array into a data container class with accessor methods, and then use key-value observing to observe when the array that backs the container object is changed (you cannot use KVO on an NSArray
directly). 您可以使用访问器方法将数组抽象为数据容器类,然后使用键值观察来观察何时更改了支持容器对象的数组(您无法直接在
NSArray
上使用KVO)。
A simple example of a class used as an abstraction on top of an array follows. 下面是一个用作数组顶部抽象的类的简单示例。 You use its
insertObject:inDataAtIndex:
and removeObjectFromDataAtIndex:
methods instead of directly accessing the with addObject:
and removeObject:
. 您可以使用其
insertObject:inDataAtIndex:
和removeObjectFromDataAtIndex:
方法,而不是直接访问with addObject:
和removeObject:
.
// DataContainer.h
@interface DataContainer : NSObject
// Convenience accessor
- (NSArray *)currentData;
// For KVC compliance, publicly declared for readability
- (void)insertObject:(id)object inDataAtIndex:(NSUInteger)index;
- (void)removeObjectFromDataAtIndex:(NSUInteger)index;
- (id)objectInDataAtIndex:(NSUInteger)index;
- (NSArray *)dataAtIndexes:(NSIndexSet *)indexes;
- (NSUInteger)countOfData;
@end
// DataContainer.m
@interface DataContainer ()
@property (nonatomic, strong) NSMutableArray *data;
@end
@implementation DataContainer
// We'll use automatic notifications for this example
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
{
if ([key isEqualToString:@"data"]) {
return YES;
}
return [super automaticallyNotifiesObserversForKey:key];
}
- (id)init
{
self = [super init];
if (self) {
// This is the ivar which provides storage
_data = [NSMutableArray array];
}
return self;
}
// Just a convenience method
- (NSArray *)currentData
{
return [self dataAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self countOfData])]];
}
// These methods enable KVC compliance
- (void)insertObject:(id)object inDataAtIndex:(NSUInteger)index
{
self.data[index] = object;
}
- (void)removeObjectFromDataAtIndex:(NSUInteger)index
{
[self.data removeObjectAtIndex:index];
}
- (id)objectInDataAtIndex:(NSUInteger)index
{
return self.data[index];
}
- (NSArray *)dataAtIndexes:(NSIndexSet *)indexes
{
return [self.data objectsAtIndexes:indexes];
}
- (NSUInteger)countOfData
{
return [self.data count];
}
@end
The reason that we do this is so we can now observe changes made to the underlying array. 我们这样做的原因是我们现在可以观察对底层数组所做的更改。 This is done through Key Value Observing .
这是通过Key Value Observing完成的 。 A simple view controller that instantiates and observes a data controller is shown:
显示了一个实例化和观察数据控制器的简单视图控制器:
// ViewController.h
@interface ViewController : UIViewController
@end
// ViewController.m
@interface ViewController ()
@property (nonatomic,strong) DataContainer *dataContainer;
@end
@implementation ViewController
static char MyObservationContext;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Instantiate a DataContainer and store it in our property
_dataContainer = [[DataContainer alloc] init];
// Add self as an observer. The context is used to verify that code from this class (and not its superclass) started observing.
[_dataContainer addObserver:self
forKeyPath:@"data"
options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew)
context:&MyObservationContext];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
// Check if our class, rather than superclass or someone else, added as observer
if (context == &MyObservationContext) {
// Check that the key path is what we want
if ([keyPath isEqualToString:@"data"]) {
// Verify we're observing the correct object
if (object == self.dataContainer) {
NSLog(@"KVO for our container property, change dictionary is %@", change);
}
}
}
else {
// Otherwise, call up to superclass implementation
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Insert and remove some objects. Console messages should be logged.
[self.dataContainer insertObject:[NSObject new] inDataAtIndex:0];
[self.dataContainer insertObject:[NSObject new] inDataAtIndex:1];
[self.dataContainer removeObjectFromDataAtIndex:0];
}
- (void)dealloc
{
[_dataContainer removeObserver:self forKeyPath:@"data" context:&MyObservationContext];
}
@end
When this code runs, three changes to the data are observed by the view controller and logged to the console: 运行此代码时,视图控制器会观察到对数据的三次更改并将其记录到控制台:
KVO for our container property, change dictionary is {
indexes = "<NSIndexSet: 0x8557d40>[number of indexes: 1 (in 1 ranges), indexes: (0)]";
kind = 2;
new = (
"<NSObject: 0x8557d10>"
);
}
KVO for our container property, change dictionary is {
indexes = "<NSIndexSet: 0x715d2b0>[number of indexes: 1 (in 1 ranges), indexes: (1)]";
kind = 2;
new = (
"<NSObject: 0x71900c0>"
);
}
KVO for our container property, change dictionary is {
indexes = "<NSIndexSet: 0x8557d40>[number of indexes: 1 (in 1 ranges), indexes: (0)]";
kind = 3;
old = (
"<NSObject: 0x8557d10>"
);
}
While this is somewhat complex (and can get much more involved), this is the only way to be notified automatically that a mutable array's contents were changed. 虽然这有点复杂(并且可以更多地涉及),但这是自动通知可变数组的内容被更改的唯一方法。
What is can do is - After updating your Array send a Notification (NSNotificationCenter) and this notification will be received by all the controllers. 可以做的是 - 更新阵列后发送通知(NSNotificationCenter),所有控制器都会收到此通知。 On receiving the notificaiton the controller should do [tableview reloaddata].
收到通知后,控制器应该执行[tableview reloaddata]。
Code example : 代码示例 :
// Adding an observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateTable:) name:@"arrayUpdated" object:nil];
// Post a notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"arrayUpdated" object:nil];
// the void function, specified in the same class where the Notification addObserver method has defined
- (void)updateTable:(NSNotification *)note {
[tableView reloadData];
}
If you want to use shiny blocks you can do this 如果你想使用闪亮的块,你可以这样做
// Create an instance variable for your block holder in your interface extension
@property (strong) id notificationHolder;
// Listen for notification events (In your TableView class.
self.notificationHolder = [[NSNotificationCenter defaultCenter] addObserverForName:@"NotificationName"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSLog(@"Received notification");
}];
Then in dealloc (or when you don't use it anymore) 然后在dealloc(或当你不再使用它时)
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self.notificationHolder];
}
Then in some other class 然后在其他一些班级
// Send a notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationName" object:nil];
Ask if something is not clear! 询问是否有不清楚的事情! Hope it helps!
希望能帮助到你!
EDIT DUE TO COMMENT 编辑由于评论
The " YourEvent " is the name of the notification, this means that you can name it to whatever you want. “ YourEvent ”是通知的名称,这意味着您可以将其命名为您想要的任何名称。 (Perhaps " UpdateArrayNotification could be a good name?)
(也许“ UpdateArrayNotification可能是一个好名字?)
Something to think about: Note that you can have several observers for the same notification. 需要考虑的事项:请注意,您可以为同一通知提供多个观察者。 This means that one 'post' will be snapped up by all observers.
这意味着所有观察者都会抢断一个“帖子”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.