2012-07-08 31 views
0

我正在嘗試設置和使用大中央調度一個NSURL,但它看來,變量設置和訪問,直到您嘗試訪問它的宏偉中心調度塊之外設置變量。與大中央調度無法找回

-(void)viewDidLoad { 

[super viewDidLoad]; 

dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
dispatch_async(backgroundQueue,^{ 

    self.ubiquitousURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; 

    NSLog(@"ubiq inside: %@", self.ubiquitousURL); 

    if (self.ubiquitousURL) { 

     self.iCloudDocURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@Documents", self.ubiquitousURL]]; 
     self.iCloudDocString = [self.iCloudDocURL absoluteString]; 

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadFiles) name: UIApplicationDidBecomeActiveNotification object:nil]; 

    } else { 

     /* change to the main queue if you want to do something with the UI. For example: */ 
     dispatch_async(dispatch_get_main_queue(),^{ 

      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Please enable iCloud" message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; 

      [alert show]; 

     }); 

    } 

}); 


NSLog(@"ubiq outside: %@", self.ubiquitousURL); 

} 

第一NSLog其中,開始與ubiq inside返回正確的URL,而ubiq outside返回null。我使用ARC,所以不需要提及內存或類似的東西......這是一個GCD問題。

你知道爲什麼self.ubiquitousURL是無法訪問的GCD塊外?謝謝。

回答

3

dispatch_async表示「稍後運行」。因此,塊內的代碼不會立即運行;它在稍後的時間運行,在「外部」NSLog呼叫已經運行之後。例如,如果您要在調用NSLog之前放入sleep(5),您可能會看到該值。 (你應該沒有真正做的是,在實際的代碼,雖然,這將基本上凍結應用五秒鐘。)

如果你想在主隊列中運行更多的代碼,你已經設置該屬性後,做是這樣的:

dispatch_async(backgroundQueue,^{ 
    self.ubiquitousURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; 

    NSLog(@"ubiq inside: %@", self.ubiquitousURL); 

    if (self.ubiquitousURL) { 
     self.iCloudDocURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@Documents", self.ubiquitousURL]]; 
     self.iCloudDocString = [self.iCloudDocURL absoluteString]; 

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadFiles) name: UIApplicationDidBecomeActiveNotification object:nil]; 

     // ************** NEW HOTNESS HERE ************** 
     dispatch_async(dispatch_get_main_queue(),^{ 
      NSLog(@"ubiq outside: %@", self.ubiquitousURL); 
     }); 
    } else { 
     /* change to the main queue if you want to do something with the UI. For example: */ 
     dispatch_async(dispatch_get_main_queue(),^{ 
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Please enable iCloud" message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
      [alert show]; 
     }); 
    } 
}); 

替換的方法調用NSLog線做實際的工作,如果這就是你想要做什麼,一旦你檢索的iCloud URL。

+0

這看起來不錯,謝謝!由於'dispatch_async'有一個延遲,我應該使用'dispatch_sync'嗎?這有什麼問題嗎? – 2012-07-08 00:44:39

+2

'dispatch_sync'會暫停應用的主隊列,直到塊完成,在這種情況下意味着直到iCloud響應您的請求。連接不好的用戶(比如紐約的AT&T用戶)可能會延遲幾分鐘。用戶會認爲該應用「已凍結」,並且如果此代碼在您的應用啓動時運行,則iOS可能會將其關閉,因爲它啓動得太慢。換句話說,我強烈建議不要在這裏使用'dispatch_sync'。在內部'dispatch_async'調用中做任何你想做的事情。 – 2012-07-08 00:49:55

+0

「dispatch_async」表示「稍後運行」。因此,塊內部的代碼不會立即運行......「此外,即使block *被立即調度,它可能無法達到它分配給ubiquitousURL屬性的位置,然後該方法中的代碼嘗試檢索它。這是一個直接的競爭條件。 – 2012-07-18 06:08:26

4

您正在進行異步調用。所以這行NSLog(@"ubiq outside: %@", self.ubiquitousURL);將得到執行,不管你在backgroundQueue中的代碼是否完成。

您會先看到外部日誌,然後看到內部日誌。