有人可以向我解释一下特别应该在iOS主线程中使用哪些代码行?
我有以下内容:
- (void)asyncWorkOnLayingOutSKUs:(UILongPressGestureRecognizer *)gesture andBlock:(void (^)(BOOL))completion {
__block NSTimeInterval totalTi = -[NSDate timeIntervalSinceReferenceDate];
//
dispatch_queue_t callerQ = dispatch_get_current_queue();
dispatch_queue_t loadingQ = dispatch_queue_create("ff.aq", NULL);
dispatch_async(loadingQ, ^{
//Code below can be placed here and then I used: dispatch_async(dispatch_get_main_queue(), ^{ //code here that must go on main thread }); in order to make it work
BOOL trueBool = YES;
//
dispatch_async(callerQ, ^{
totalTi += [NSDate timeIntervalSinceReferenceDate];
NSLog(@"Performance: %g sec", totalTi);
completion(trueBool);
if(completion){
//For now, there is no multithreading since all code is placed on main thread...
self.timingDate = [NSDate date];
switch (self.lastButtonPressedForDragTags) {
case 1:{
self.slotOneButtonIndex = gesture.view.tag-1;
} break;
case 2:{
self.slotTwoButtonIndex = gesture.view.tag-1;
} break;
case 3:{
self.slotThreeButtonIndex = gesture.view.tag-1;
} break;
case 4:{
self.slotFourButtonIndex = gesture.view.tag-1;
} break;
case 5:{
self.slotFiveButtonIndex = gesture.view.tag-1;
} break;
}
int touchedtag = gesture.view.tag;
UIView* thisView;
UIScrollView* thisScrollView;
switch (gesture.view.superview.superview.tag) {
case -1:{
thisView = self.dragTagsScrollViewContainer;
thisScrollView = self.dragTagsScrollView;
} break;
case -2:{
thisView = self.SKUTagsScrollViewContainer;
thisScrollView = self.SKUTagsScrollView;
} break;
case -3:{
thisView = self.otherTagsScrollViewContainer;
thisScrollView = self.otherTagsScrollView;
} break;
case -4:{
thisView = self.leftDraggedTagsScrollViewContainer;
thisScrollView = self.leftDraggedTagsScrollView;
} break;
}
UIButton *button = (UIButton*)[thisView viewWithTag:touchedtag];
if(![button isSelected]){
[self setButtonSelected:button];
}
else{
[self setButtonDeselected:button];
}
//Get the position of the button RELATIVE to the superview by subtracting the content offset for x direction:
CGRect buttonPosition = CGRectMake(button.frame.origin.x - thisScrollView.contentOffset.x, button.frame.origin.y, button.frame.size.width, button.frame.size.height);
CGRect sizeOfScrollView = CGRectMake(0, 0, thisScrollView.frame.size.width, thisScrollView.frame.size.height);
if(CGRectContainsRect(sizeOfScrollView, buttonPosition)){}
else{
//extend scrollview to L or R
CGPoint rightBottomEdgeOfButton = CGPointMake(buttonPosition.origin.x + buttonPosition.size.width, buttonPosition.origin.y + buttonPosition.size.height);
CGRect intersection = CGRectIntersection(sizeOfScrollView, buttonPosition);
float amountToMove;
float currentXDirectionOffset = thisScrollView.contentOffset.x;
CGPoint newOffset;
if (CGRectContainsPoint(sizeOfScrollView, rightBottomEdgeOfButton)){
//Need to move Left
amountToMove = button.frame.size.width - intersection.size.width + 5;
}
else{
//Need to move Right
amountToMove = -(button.frame.size.width - intersection.size.width + 5);
}
newOffset = CGPointMake(currentXDirectionOffset-amountToMove, thisScrollView.contentOffset.y);
[thisScrollView setContentOffset:newOffset];
}
[self.SKUTagsScrollViewContainer removeFromSuperview];
NSMutableArray* arrayToUse = [[NSMutableArray alloc]initWithArray:[self getIntersectionArray]];
[self populateScrollViewWithArray:arrayToUse andScrollView:self.SKUTagsScrollView withContainer:self.SKUTagsScrollViewContainer andmaxNumberOfRowsForScrollView:6];
#ifdef DEBUG
NSLog(@"Time taken to AFTER populateScrollViewWithArray: %g and for %d controls", [[NSDate date] timeIntervalSinceDate:self.timingDate], [arrayToUse count]);
#endif
}
});
});
dispatch_release(loadingQ);
}
现在显然加载q没有任何内容,方法populateScrollViewWithArray
基本上在UIScrollView上排列了一些按钮。我发现我能够包装'我认为对dispatch_async(dispatch_get_main_queue(), ^{});
中的ui渲染至关重要的任何代码,然后我可以将if(completion){}
中显示的所有代码放在加载q上。
这两个选项都有效,我测量了性能,发现我得到了类似的结果。
我的问题是我是iOS的新手,我想知道:
如何使用线程最大化性能?
究竟应该在主线程上进行什么?在方法populateScrollViewWithArray
中,我执行了以下操作:
dispatch_async(dispatch_get_main_queue(), ^{
[scrollview addSubview:scrollViewContainer];
[self.view addSubview:scrollview];
});
但我做了一些事情,比如创建标签,创建按钮并在加载q上添加手势(没有在dispatch_async(dispatch_get_main_queue(), ^{});
除了阅读文档'以外,还有人能给我一个简明的解释吗?因为我经常发现Apple文档很长时间。有点像这个问题......
答案 0 :(得分:2)
一般规则是大多数UIKit类在后台线程中使用是不安全的,除非文档明确说明(有时文档不一致,有时它会中断,例如UIKit绘图应该是线程安全的,因为4.0但在iOS 5.x中被破坏了。
IIRC文档还建议在后台线程上创建视图(例如通过加载笔尖)是安全的,只要它们没有被添加到窗口中。尽管如此,我还没有对此进行浸泡测试,因此可能存在一些不安全的边缘情况(UIWebView可能就是其中之一)。
它还稍微更复杂,因为根据GKTapper example code,某些UIKit类对后台线程的发布不安全:
如果在辅助队列上执行的块中视图控制器引用, 视图控制器可以在主队列之外被释放(并且dealloc&#d; d)。 即使在主线程上安排了实际的块,也是如此。 ... UIKit视图控制器只能在主线程上访问,因此上面的代码片段可能导致微妙和困难追踪错误。
您的代码在后台线程上运行的块(由a引用的块)中捕获self
和gesture
,这意味着它们可能会在后台线程上释放,这可能偶尔会崩溃。< / p>
其他挑剔:
totalTi
不需要是__block
变量。loadingQ
应替换为全局队列。if(completion)
始终为true(如果completion(trueBool)
为NULL,则上面一行中出现completion
。)