使用Array执行键值观察没有做任何事情

时间:2012-04-21 21:10:02

标签: objective-c ios xcode key-value-observing

我有两个视图,我的第一个视图是class1.m,第二个视图是class2.m。当在第一个视图中的工具栏上按下按钮时,我的第二个视图被初始化为弹出窗口。我在第二个视图中有一个数组,如果按下任何行,则添加对象。我正在尝试在我的第一个视图中设置一个KVO,这样我就可以在第一个视图中从第二个视图访问allSelectedFocus数组,但它不起作用。我意识到我没有调用removeObserver,但我不知道在哪里调用它,没有它在使用之前移除观察者。如果有人知道有任何更好的方法可以做到这一点,我愿意接受建议,但是如果有人可以让它发挥作用,那真的很棒。

// class2.m

#import "class2.h"
#import "class1.h"

@implementation class2

@synthesize selectedFocus = _selectedFocus;
@synthesize focusArray = _focusArray;
@synthesize allSelectedFocus = _allSelectedFocus;

- (void)viewDidLoad
{
_focusArray = [[NSArray alloc]initWithObjects:@"Balance",@"Bevægelse",@"Elementskift",@"Vejrtrækning",@"Alle",nil];

[super viewDidLoad];

}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return _focusArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}


NSString *cellValue = [_focusArray objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;

return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_selectedFocus = [[_focusArray objectAtIndex:indexPath.row] stringByAppendingString:@","];
if(![[self mutableAllSelectedFocus] containsObject:_selectedFocus])
   {
       //add object to array, if it's not already there
       [[self mutableAllSelectedFocus] addObject:_selectedFocus];
   }
else
    {
        //remove object from array, if it's already there
        [[self mutableAllSelectedFocus] removeObject:_selectedFocus];   
    }
 }

-(NSMutableArray *)allSelectedFocus
{
if(_allSelectedFocus == nil)
{
    _allSelectedFocus = [[NSMutableArray alloc]init];
}
return _allSelectedFocus;
}

-(NSMutableArray *)mutableAllSelectedFocus
{
return [self mutableArrayValueForKey:@"allSelectedFocus"];
}
@end

// class1.m

#import "class1.h"
#import "class2.h"

@implementation class1
- (void)viewDidLoad
{
[super viewDidLoad];

 if(_focusTag == nil)
{
    _focusTag = [[class2 alloc]init];
}

[_focusTag addObserver:self forKeyPath:@"selectedFocus" options:NSKeyValueObservingOptionNew context:NULL];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([keyPath isEqualToString:@"allSelectedFocus"])
{
NSLog(@"%@", [object valueForKeyPath:keyPath]);
}
}

2 个答案:

答案 0 :(得分:4)

我怀疑这是NSArray objects are not observable或更广泛违反KVC compliance这一事实的函数。无论如何,只为NSArray对象实现manual change notification,你应该没问题。我刚刚测试了对N​​SArray对象的更改(添加对象)并且没有发生自动通知,但是当我添加手动通知时,它工作正常。 (但奇怪的是,NSKeyValueObservingOptionOld没有按预期工作,显示新值而不是旧值。)仅供参考,这是一个更新方法的示例,它使用手动通知向我的对象NSMutableArray添加内容:

- (void)addToMyArray:(id)obj
{
    [self willChangeValueForKey:@"myArray"];
    [_myArray addObject:obj];
    [self didChangeValueForKey:@"myArray"];
}

<强>更新

顺便说一下,如果你需要NSKeyValueObservingOptionOld,你可以这样做:

- (void)addToMyArray:(id)obj
{
    NSMutableArray *tempArray = [NSMutableArray arrayWithArray:_myArray];
    [tempArray addObject:obj];
    [self setMyArray:tempArray];
}

这样,你不需要手动通知,你可以检索旧值和新值,但它似乎也是对内存的低效使用,所以有利有弊。

答案 1 :(得分:1)

只是提醒一下,在任何时候你都没有使用访问器方法来设置/获取你的属性。这意味着KVO将无法运作。我相信KVO依赖于通过访问器获取/设置属性。

我不确定您要使用该应用程序完成的任务,但我将一些可能有用的代码放在一起。我在代码中进行了评论,所以我不会在这个答案中解释它。

我会像你一样从class2开始:

#import <UIKit/UIKit.h>

@interface Class2ViewController : UITableViewController

@property (nonatomic, strong) NSArray *focusArray;
@property (nonatomic, strong) NSMutableArray *allSelectedFocus;

// This is a readonly property that will return a mutable array of the allSelectedFocus      property
// This gives you the ability to have automatic KVO if you add/remove using this property
// You won't have to wrap your calls to will/didChangeValueForKey:
@property (nonatomic, readonly, strong) NSMutableArray *mutableAllSelectedFocus;

@end


#import "Class2ViewController.h"
#import "Class1ViewController.h"


@implementation Class2ViewController

@synthesize focusArray = _focusArray;
@synthesize allSelectedFocus = _allSelectedFocus;


- (void)viewDidLoad
{
    [super viewDidLoad];

    // This is what you have 
    // FYI you are accessing the iVar directly, not sure if that matters in your app or not
    _focusArray = [[NSArray alloc] initWithObjects:@"Balance",@"Bevægelse",@"Elementskift",@"Vejrtrækning",@"Alle",nil];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Grab the string of interest from the _focusArray --> this is direct access again which I imagine is fine
    NSString *selectedFocus = [[_focusArray objectAtIndex:indexPath.row] stringByAppendingString:@","];

    // Use the new mutableAllSelectedFocus property to check if the array doesn't contain the string of interest
    if (![[self mutableAllSelectedFocus] containsObject:selectedFocus]) {

        // If it doesn't contain it, add it using the mutableAllSelectedFocus property
        [[self mutableAllSelectedFocus] addObject:selectedFocus];
    }

}

// This is getter that lazily instantiates your _allSelectedFocus array
- (NSMutableArray *)allSelectedFocus
{
    // Check to see if the backing iVar is nil
    if (_allSelectedFocus == nil) {

        // If it is, create an empty mutable array
        _allSelectedFocus = [[NSMutableArray alloc] init];
    }

    // return the array
    return _allSelectedFocus;
}

// This is our new property
- (NSMutableArray *)mutableAllSelectedFocus
{
    // mutableArrayValueForKey: returns a mutable array for the given key (property)
    // Allows us better KVO and efficiency with changing properties
    return [self mutableArrayValueForKey:@"allSelectedFocus"];
}

现在上课1:

#import "Class1ViewController.h"
#import "Class2ViewController.h"

@implementation Class1ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // If you are using ARC, this instance will be deallocated after -viewDidLoad
    // You will want to store this in an instance variable if you need to keep it around
    Class2ViewController *class2ViewController = [[Class2ViewController alloc] init];

    [class2ViewController addObserver:self
                           forKeyPath:@"allSelectedFocus"
                              options:NSKeyValueObservingOptionNew
                              context:NULL];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"allSelectedFocus"]) {

        NSLog(@"%@", [object valueForKeyPath:keyPath]);
    }
}

我不确定代码中的这一更改是否会对您的应用程序有所帮​​助。我会做的两件事是,如果你还没有阅读键值编码和键值观察指南,请阅读这个post关于多对关系和属性。

如果我出错了,请发表评论。

祝你好运。