【问题标题】:Key value observing with Array not doing anything使用 Array 观察键值不做任何事情
【发布时间】:2012-04-21 21:10:02
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

    我怀疑这要么是NSArray objects are not observable 的函数,要么是对KVC compliance 的更广泛的违反。无论如何,只需为 NSArray 对象实现manual change notification 就可以了。我刚刚测试了对 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];
    }
    

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

    【讨论】:

    • 我应该在哪里实现这个方法?
    • 我会将它放在发送通知的对象中,该对象具有正在更改的属性。在您的示例中,这将是 class2。
    【解决方案2】:

    请注意,您绝不会使用访问器方法来设置/获取您的属性。这意味着 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,如果你还没有阅读这个post 对多关系和属性。

    如果我有什么不对的地方,请发表评论。

    祝你好运。

    【讨论】:

    • 我已经更新了上面的代码,但仍然没有任何反应。我想 NSLog() 发生什么变化,所以我可以看到它确实发生了变化。我最终想要做的是将这个数组放入 class1 中的其他数组中。如果我可以观察 _selectedFocus 并将其传递给我的 class1,一旦它发生变化,那么我可以将该值放入 class1 中的 NSMutableArray 中。所以也许有一种方法可以观察一个 NSString,这在我的情况下会起作用吗?
    猜你喜欢
    • 2021-12-24
    • 2011-03-29
    • 1970-01-01
    • 2020-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多