1

特に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 レンダリングに不可欠と思われるコードを「ラップ」できることがわかりました。dispatch_async(dispatch_get_main_queue(), ^{});次に、ここに示すすべてのコードを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のドキュメントが非常に長くなっていることに気付くので、「ドキュメントを読む」以外の簡潔な説明を誰かに教えてもらえますか。この質問に少し似ています.....

4

1 に答える 1

2

一般的なルールは、ほとんどの UIKit クラスは、ドキュメントに特に明記されていない限り、バックグラウンド スレッドから使​​用するのは安全ではないということです (ドキュメントに一貫性がなく、壊れている場合もあります。たとえば、4.0 以降、UIKit の描画はスレッドセーフであると想定されていましたが、壊れていました)。 iOS 5.x で)。

IIRC のドキュメントでは、ビューがウィンドウに追加されていない限り、バックグラウンド スレッドで (たとえば nib をロードすることによって) ビューを作成することも安全であることが示唆されています。ただし、これは浸水テストを行っていないため、安全ではないエッジケースがいくつかある可能性があります (UIWebView はおそらくその 1 つです)。

GKTapper のサンプル コードによると、一部の UIKit クラスはバックグラウンド スレッドから解放するのが安全でないため、それよりも少し複雑です。

ビュー コントローラがセカンダリ キューで実行されるブロックで参照されている場合、そのビュー コントローラはメイン キューの外で解放 (および解放) される可能性があります。 これは、実際のブロックがメイン スレッドでスケジュールされている場合でも当てはまります。... UIKit ビュー コントローラーはメイン スレッドでのみアクセスする必要があるため、上記のスニペットは微妙で追跡が困難なバグに つながる可能性があります。

コードは、バックグラウンド スレッドで実行される (a によって参照されるブロック) ブロックをキャプチャselfします。gesture

その他の小ネタ:

  • totalTi__block変数である必要はありません。
  • loadingQグローバル キューに置き換える必要があります。
  • if(completion)は常に true です (上記の行でis NULLcompletion(trueBool)の場合にクラッシュします)。completion
  • コードの大部分を、6 レベルのインデントではなく、VC の補完メソッドに移動できます。
于 2013-02-23T00:15:11.850 に答える