2011-12-05 78 views
2

我用導航控制器設置了一些視圖。當我搖動手機時,我希望能夠回到原始視圖。首先,下面是我在AppDelegate中的代碼片段:爲什麼popToRootViewContoller凍結或需要很長時間才能執行?

- (void)startAccelerometerUpdates 
{ 

[motionManager startDeviceMotionUpdatesToQueue:queue withHandler:^(CMDeviceMotion *motion, NSError *error) { 
    // based from 
    // http://stackoverflow.com/questions/5214197/simple-iphone-motion-detect/5220796#5220796 
    float accelerationThreshold = 1; // or whatever is appropriate - play around with different values 
    CMAcceleration userAcceleration = motion.userAcceleration; 
    if (fabs(userAcceleration.x) > accelerationThreshold || 
     fabs(userAcceleration.y) > accelerationThreshold || 
     fabs(userAcceleration.z) > accelerationThreshold) { 



     if(!self->isRoot) { 
      NSLog(@"Stopping motion manager"); 
      [motionManager stopDeviceMotionUpdates]; 
      NSLog(@"popping to top view controller"); 
      [navcon popToRootViewControllerAnimated:YES]; 
      NSLog(@"Done popping"); 
     } 

    } 

}]; 
} 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    ..... 

    motionManager = [[CMMotionManager alloc] init]; 
    motionManager.deviceMotionUpdateInterval = .5; 

    isRoot = malloc(sizeof(BOOL)); 
    self->isRoot = NO; 
    [self startAccelerometerUpdates]; 

    [navcon pushViewController:main animated:NO]; 
    .... 
} 

我期待着對popToRoot的調用將立即生效。但是,大約需要30秒。有趣的是,注意頂部的那個按鈕可以手動返回到上一頁的按鈕在這一點上不起作用。手機似乎正在做很多工作來凍結按鈕。所以,我肯定在這裏做錯了什麼。

它想,也許我一直在呼喚的popToRootViewController幾次,所以我增加了一個檢查「isRoot」當你在代碼中看到(請不要分心爲什麼BOOL是一個指針,我有一個理由)。

+0

顯示實際的日誌可能會有幫助。 – tia

+0

日誌就是那三條線......停下來,彈出,完成了我在代碼中的工作。代碼運行通過該方法沒有問題。 – EDJ

回答

4

您的運動處理程序塊似乎打算在後臺隊列上運行。 UIKit方法(如popToRootViewController)只能在主線程上調用,而且不遵循該規則的行爲通常與您所描述的類似。

-performSelectorOnMainThread:withObject:waitUntilDone是確保您的UIKit的代碼在主線程上運行的最簡單的方法,但由於-popToRootViewControllerAnimated:需要一個非對象參數,它需要多一點的工作。最簡單的方法是添加另一種方法是不帶任何參數:

-(void)popToRootView { 
    [navcon popToRootViewControllerAnimated:YES]; 
} 

,然後更新您的塊調用主線程上的方法:

if(!self->isRoot) { 
    [motionManager stopDeviceMotionUpdates]; 
    [self performSelectorOnMainThread:@selector(popToRootView) withObject:nil waitUntilDone:NO]; 
} 
+0

它從didFinishLaunchingWithOptions中調用(我更新了我的代碼)。我不確定這是後臺線程還是主線程。對不起,這裏對IOS很新穎:) – EDJ

+0

'-startAcceleratorUpdates'方法可能在主線程中調用,但是您定義的回調函數(withHandler參數爲'-startDeviceMotionUpdatesToQueue:withHandler')幾乎肯定會是從傳遞給另一個參數的隊列調用後臺線程。 –

+0

天才,天才!感謝您的解釋和解決方案。 – EDJ

相關問題