任何人都可以解释" dispatch_async"在这个例子..?

时间:2014-05-07 11:10:35

标签: ios objective-c multithreading grand-central-dispatch message-queue

我想要做的是实现键值观察模式。

我有MasterViewController,DetailViewController和名为Animal的随机类,它只有一个名为“name”的属性。(顺便说一下,这个项目是从 Master-View控制器模板构建的

// Animal.h
#import <Foundation/Foundation.h>

@interface Animal : NSObject
@property NSString *name;
@end

在detailViewController中只有一个标签使用segue显示来自动物类的name属性。并且,我也将Observer添加到动物Obj。

//detailViewController.h
#import <UIKit/UIKit.h>

@interface DetailViewController : UIViewController

@property (strong, nonatomic) id detailItem;
@property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;

@end


//implementation 
@implementation DetailViewController

- (void)setDetailItem:(id)newDetailItem
{
    if (_detailItem != newDetailItem) {
        _detailItem = newDetailItem;

        [newDetailItem addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

        // Update the view.
        [self configureView];

    }
}

-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    [self configureView];
}

- (void)configureView
{
    // Update the user interface for the detail item.
    if (self.detailItem) {
       self.detailDescriptionLabel.text = [self.detailItem name];
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    [self configureView];
}

在MasterViewController中,这是一个tableViewController,每当按下“+”栏按钮时,它会将单元格的细节设置为Animal类中的名称。而且,此时在这个方法中(insertNewObject :)我正在通过让它进入睡眠来模拟下载某些东西(5); 然后,它会将随机数分配给来自animal的name属性。 当你更改名称属性时,因为我已经将Observer添加到Animal,它会通知我并“更新”我的标签! SO,Sinarrio就是按下“+”按钮后,单击刚刚插入的单元格并等待原始标签更改。

- (void)insertNewObject:(id)sender
{
    if (!_objects) {
        _objects = [[NSMutableArray alloc] init];
    }

    Animal *animal = [[Animal alloc]init];
    animal.name = [NSString stringWithFormat:@"animal number %d", _objects.count+1 ];
    [_objects insertObject: animal atIndex:0];

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        sleep(5);// simulating downloading.

        NSLog(@"3");
        NSLog(@"4");
        // assign random number.
        animal.name = [NSString stringWithFormat:@"animal number %d", rand()];

        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"7");
            [self.tableView reloadData]; // **it got called after excuting NSLog(@"8") why..?**
            NSLog(@"8");
        });
        NSLog(@"5");
        NSLog(@"6");
    });

    NSLog(@"2");
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    NSLog(@"1");
    Animal *animal = _objects[indexPath.row];
    cell.textLabel.text = [animal name];

    return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"showDetail"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        Animal *animal = _objects[indexPath.row];
        [[segue destinationViewController] setDetailItem:animal];
    }
}

所以,这就是我的有线行为。 至于调度线程的oder,我打印了数字,但有些时候它有不同的顺序。 但是,当我得到这个订单时,我真的不明白: 1 2 3 4 7 5 6 8 1 我认为在单线程执行中,它不应该跳转,特别是7 8 1订单部分..

另外一个问题是,在3和4之后,因为它改变了name属性,我的configure方法立刻被调用但是它没有更新或刷新任何东西,直到..实际上在一段时间之后5 6 7 8印刷

最后, 按“+”按钮后,从细节到主视图来回然后  你有这个错误和为什么.. enter image description here

PS:当KVO在name属性更改后调用My configure方法时,当我调试时,name属性已更改但它没有更新..

2 个答案:

答案 0 :(得分:0)

首先,对于您的第一个问题,您需要了解调度员的工作方式

使用 global_queue 中的dispatch_async功能(即并发执行主题的顺序可以每次更改。不是不变的。要更好地理解,请阅读我在stackoverflow上写的文章:

How does the dispatcher work when mixing sync/async with serial/concurrent queue?

另一件事是您将@property NSString *name声明为atomic。实际上,当您不写任何内容时,atomic是默认值。我不知道你是否自愿提出这个问题,但无论如何,我会写:

@property (copy, nonatomic) NSString *name;

尝试重新运行代码并阅读我的文章。现在我会更好地阅读你的帖子,我可以在这个回复中写下其他内容。

答案 1 :(得分:0)

看起来animal.name是不可变的。多项任务伤害。