1

我有两个视图,我的第一个视图是 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]);
}
}
4

2 回答 2

4

我怀疑这要么是NSArray 对象不可观察的事实,要么是更广泛地违反了KVC 合规性。无论如何,只需为 NSArray 对象实现手动更改通知就可以了。我刚刚测试了对 NSArray 对象的更改(添加对象)并且没有发生自动通知,但是当我添加手动通知时,它工作正常。(尽管奇怪的是,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];
}

这样一来,就不需要手动通知了,新旧值都可以检索,但也显得内存使用效率低下,所以有利有弊。

于 2012-04-22T03:11:00.090 回答
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]);
    }
}

我不确定这种代码更改是否会对您的应用程序有所帮​​助。如果您还没有阅读 Key-Value Coding 和 Key-Value Observing Guides,我会做两件事,并阅读这篇关于多关系和属性的文章。

如果我有什么问题,请发表评论。

祝你好运。

于 2012-04-22T06:31:04.057 回答