16

たくさん検索しましたが、役立つコードやチュートリアルが見つかりませんでした。

私のアプリケーションでは、60秒ごとに更新される可変配列があります。

配列内のオブジェクトは、複数のViewControllerのテーブルビューによって表示されています。

配列の値が変更または更新された場合にのみ、テーブルビューを自動的に再読み込みしたい。

このために、可変配列にオブザーバーを追加したいと思います。つまり、配列の値が変更された場合、たとえば特定のメソッドを呼び出す必要があります。

-(void)ArrayUpdatedNotification:(NSMutableArray*)array
{
    //Reload table or do something
} 

前もって感謝します。

4

3 に答える 3

19

アクセサメソッドを使用して配列をデータコンテナクラスに抽象化し、Key-Value監視を使用して、コンテナオブジェクトをサポートする配列が変更されたことを監視できます(KVOをNSArray直接使用することはできません)。

配列の上で抽象化として使用されるクラスの簡単な例を次に示します。withと。に直接アクセスする代わりに、そのinsertObject:inDataAtIndex:andメソッドを使用します。removeObjectFromDataAtIndex: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

これを行う理由は、基になる配列に加えられた変更を観察できるようにするためです。これは、KeyValueObservingを介して行われます。データコントローラーをインスタンス化して監視する単純なビューコントローラーを示します。

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

このコードが実行されると、データへの3つの変更がView Controllerによって監視され、コンソールに記録されます。

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>"
        );
    }

これはやや複雑ですが(さらに複雑になる可能性があります)、可変配列の内容が変更されたことを自動的に通知する唯一の方法です。

于 2013-03-25T11:33:51.293 に答える
5

できることは次のとおりです。アレイを更新した後、通知(NSNotificationCenter)を送信すると、この通知がすべてのコントローラーによって受信されます。通知を受信すると、コントローラーは[tableviewreloaddata]を実行する必要があります。

コード例

// 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]; 
}
于 2013-03-25T10:32:48.637 に答える
0

光沢のあるブロックを使用したい場合は、これを行うことができます

// 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");
}];

次に、deallocで(またはもう使用しない場合)

- (void)dealloc {
     [[NSNotificationCenter defaultCenter] removeObserver:self.notificationHolder];
}

その後、他のクラスで

// Send a notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationName" object:nil];

何かがはっきりしていないか尋ねてください!それが役に立てば幸い!

コメントによる編集

YourEvent」は通知の名前です。これは、任意の名前を付けることができることを意味します。(おそらく「UpdateArrayNotificationは良い名前かもしれませんか?)

考慮すべき点:同じ通知に対して複数のオブザーバーを持つことができることに注意してください。これは、1つの「投稿」がすべてのオブザーバーによってスナップアップされることを意味します。

于 2013-03-25T10:48:29.357 に答える