1

有人請向我解釋哪些代碼行應該在iOS的主線上?在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一些按鈕。我發現我能夠'包裝'任何我認爲對於UI渲染至關重要的代碼,然後我可以將這裏顯示的所有代碼放在加載q上的if(completion){}內。

這兩個選項都起作用,我測量了性能,發現我得到了類似的結果。

我的問題是,我是新來的iOS和我想知道:

我怎樣才能最大限度地使用線程的性能?

究竟應該走到主線程?在該方法中populateScrollViewWithArray我做了以下內容:

  dispatch_async(dispatch_get_main_queue(), ^{ 

      [scrollview addSubview:scrollViewContainer]; 
      [self.view addSubview:scrollview]; 
     }); 

但我做事情喜歡創建標籤,創建按鈕和裝載q加手勢(內沒有明確包圍他們dispatch_async(dispatch_get_main_queue(), ^{});

任何人都可以點我除了'閱讀文檔'以外,我通常發現蘋果文檔相當長的囉嗦。有點像這個問題.....

+2

每次調用UIKit。 – 2013-02-22 23:58:09

+0

謝謝。對一個長期問題的簡短回答。 – 2013-02-23 00:35:44

回答

2

一般的規則是,大多數UIKit類是不安全的使用從一個後臺線程,除非文檔明確說明,否則(有時文檔使用不一致,有時會中斷,例如,從4.0開始,UIKit繪圖應該是線程安全的,但在iOS 5.x中被破壞了)。

IIRC文檔還建議在後臺線程上創建視圖(例如通過加載筆尖)是安全的,前提是它們尚未添加到窗口中。儘管如此,我還沒有對此進行浸泡測試,因此可能存在一些不安全的邊緣情況(UIWebView可能就是其中之一)。

這也是略微比這更復雜,因爲一些UIKit類根據GKTapper example code是不安全釋放從後臺線程:

如果視圖控制器在一個塊中引用它在輔助隊列上執行, 視圖控制器可以在主隊列之外釋放(並且釋放)。 即使在主線程上調度實際塊,情況也是如此。 ... UIKit視圖控制器應該只能在主線程上訪問,所以上面的代碼片段可能會導致微妙且難以追蹤錯誤

你的代碼捕獲在一個後臺線程,這意味着他們可能會在後臺線程,這有時可能會崩潰發佈運行塊(被引用的塊)selfgesture

其他吹毛求疵:

  • totalTi並不需要是一個__block變量。
  • loadingQ應替換爲全局隊列。
  • if(completion)始終爲真(completion(trueBool)在上面的行中崩潰,如果completion爲NULL)。
  • 您可以將大部分代碼移至VC中的完成方法,而不是具有6級縮進。
+0

非常感謝答案tc。它有幫助 – 2013-02-23 00:33:12

相關問題