Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 保持UISegmentedControl(除其他外)的响应性_Iphone_Objective C_Cocoa Touch_Multithreading - Fatal编程技术网

Iphone 保持UISegmentedControl(除其他外)的响应性

Iphone 保持UISegmentedControl(除其他外)的响应性,iphone,objective-c,cocoa-touch,multithreading,Iphone,Objective C,Cocoa Touch,Multithreading,我有一个分段控件用作切换。切换时,我会在表视图中切换一组内容,这需要很短但很明显的时间(插入/删除表视图中的部分、设置更改动画等)。我希望分段控件立即响应选择。因此,在分段控件的UIControlEventValueChanged事件的操作处理代码中,我执行以下操作: - (IBAction)groupingChanged:(id)sender { UISegmentedControl *seg = sender; [tableModel toggleOn:[seg select

我有一个分段控件用作切换。切换时,我会在表视图中切换一组内容,这需要很短但很明显的时间(插入/删除表视图中的部分、设置更改动画等)。我希望分段控件立即响应选择。因此,在分段控件的UIControlEventValueChanged事件的操作处理代码中,我执行以下操作:

- (IBAction)groupingChanged:(id)sender {
    UISegmentedControl *seg = sender;
    [tableModel toggleOn:[seg selectedSegmentIndex] == ToggleOnIndex];
    [self performSelectorOnMainThread:@selector(updateGrouping)
                           withObject:nil
                        waitUntilDone:NO];
}
其中,
updategroup
是:

- (void)updateGrouping {
    MXAssertMainThread();

    [tableView beginUpdates];
    ... several table updates
    [tableView endUpdates];
}
设置
waitUntilDone:NO
允许
groupingChanged
方法在调用
updategroup
之前完成,但这似乎不足以重新绘制视图。分段控件将保持不变,直到完成表格更新,然后切换

因此,我尝试修改
groupingChanged:
为更新创建一个线程,如下所示:

- (void)delayed {
    [self performSelectorOnMainThread:@selector(updateGrouping)
                           withObject:nil
                        waitUntilDone:NO];
}

- (IBAction)groupingChanged:(id)sender {
    UISegmentedControl *seg = sender;
    [tableModel toggleOn:[seg selectedSegmentIndex] == ToggleOnIndex];
    [self performSelectorInBackground:@selector(delayed) withObject:nil];
}

这确实有效。分段控件立即切换,表格很快跟随。但我对结果一点也不自信。这仅仅是在新线程启动时暂停主线程的副作用吗?这就是我需要排队更新UI的方式吗?很明显,它很粗糙。我希望有人有一个更好的模式,他们在这种情况下遵循。

如果你只是想确保分段控件得到真正快速的重新绘制,我可能不会深入线程

相反,我只需要设置一个低值的计时器,比如0.1,这应该足以让控件更新,而不会对用户造成任何明显的延迟

当我有很多工作要做,但需要快速更新UI时,我会使用这个

仍然有点“黑客”,但没有引入线程

所以


这样想吧——您所做的一切通常都是在主线程上完成的,包括UI更新

因此,在原始代码中,更新表视图的代码是在对段进行UI更新的代码之前到达的

因此,您认为给主线程一个中断允许更多的时间来完成UI更新是正确的,因为主线程被允许完成UI更新,而后台线程处理表更新


您可以尝试的另一种方法是使用带有0.0延迟的performSelector:withObject:afterDelay(这允许主线程在继续使用选择器之前处理其他事情)。它可能在performSelectorOnMainThread没有的地方工作,因为调用可能更直接,即使它们最终做的事情非常相似。

我遇到了同样的问题,并通过对UISegmentedControl进行子类化来创建延迟的UISegmentedControl来解决它

在延迟控件中,我覆盖了
addTarget:action:forControlEvents:
以捕获目标和操作。然后,当段事件发生时,我运行
NSTimer
,在设置的延迟后启动捕获的目标和操作。结果是UI得到更新以显示单击的段,并且我可以像使用UISegmentedControl一样使用DelayedUISegmentedControl:

// Follows all normal initialization patterns of UISegmentedControl
UISegmentedControl *segmentedControl = [[DelayedUISegmentedControl alloc] 
    initWithItems:[NSArray arrayWithObjects: @"First", @"Second", nil]];

// Adds a delay to the selector; default is 0.25
[segmentedControl addTarget:self action:@selector(segmentAction:) 
    forControlEvents:UIControlEventValueChanged];

如果你想下载我已经开源的控件。

这消除了中间线程,所以这是一个改进,但我不相信没有常见的非黑客模式。performSelector:withObject:afterDelay也有效,正如Kendall指出的那样。这个问题是运行循环需要完成才能更新UI。这不是真正的黑客行为,只是承认这一事实。据我所知,在不允许主线程运行其进程的情况下,无论如何都无法更新UI。当然,我知道原因。我想我希望有一个共同的模式。我认为这是常见的模式,我推荐Kendall的建议,因为performSelector语法更自然一些。此外,通过在解析选择器时使用此间接方法,您可以灵活地将任意选择器传递给方法,而不是预先确定的选择器。代码稍微少一点,更具动态性和可重用性。
// Follows all normal initialization patterns of UISegmentedControl
UISegmentedControl *segmentedControl = [[DelayedUISegmentedControl alloc] 
    initWithItems:[NSArray arrayWithObjects: @"First", @"Second", nil]];

// Adds a delay to the selector; default is 0.25
[segmentedControl addTarget:self action:@selector(segmentAction:) 
    forControlEvents:UIControlEventValueChanged];