Menggunakan @synchronized dengan operasi sinkron

Saya menggunakan subkelas UIDocument yang berpotensi memanggil metode saveToURL dari lebih dari satu utas. Oleh karena itu saya telah merangkumnya dalam fungsi pembungkus yang saya ingin buat agar thread aman:

- (void)saveWithCompletionBlock:(void(^)(TransactionDocumentReturnCode status))completion {
    @synchronized (self) {
        [self saveToURL:[self fileURL] forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success){
            // Generate returncode depending on outcome of save operation
            completion(returncode);
        }];
    }
}

Saya berasumsi bahwa panggilan ke [self saveToURL:...] akan segera kembali karena operasi penyimpanan itu sendiri terjadi di thread latar belakang, menyebabkan kunci berpotensi dilepaskan sebelum operasi penyimpanan selesai. Jadi, apakah ada cara untuk menjaga thread lain yang memanggil saveWithCompletionBlock: diblokir sampai blok penyelesaian saveToURL dipanggil?


person mashers    schedule 25.03.2016    source sumber
comment
Lihat jawaban ini untuk mengetahui dua cara menerapkannya: stackoverflow.com/a/7649768/78496   -  person chedabob    schedule 25.03.2016
comment
Terima kasih @chedabob. Apakah penggunaan GCD atau NSOperationQueue akan mengakibatkan panggilan berikutnya ke fungsi pembungkus penyimpanan diblokir hingga blok penyelesaian operasi penyimpanan selesai?   -  person mashers    schedule 25.03.2016


Jawaban (1)


Salah satu solusi potensial yang baru saja saya pikirkan adalah menambahkan properti ke subkelas UIDocument saya untuk menunjukkan apakah operasi penyimpanan sedang berlangsung, dan jika demikian, tunggu lalu coba lagi. Menggabungkan pemeriksaan dan pengaturan properti ini dalam @synchronize akan mencegah dua thread secara bersamaan membaca nilai sebagai false dan percaya bahwa mereka dapat menyimpan dokumen:

- (void)saveWithCompletionBlock:(void(^)(TransactionDocumentReturnCode status))completion {
    @synchronized(self){
        if (self.isSaving) {
            [self performSelector:@selector(saveWithCompletionBlock:) withObject:completion afterDelay:1.0];
            return;
        }

        self.isSaving = YES;
    }

    [self saveToURL:[self fileURL] forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success){
        // Generate returncode depending on outcome of save operation
        completion(returncode);
        self.isSaving = NO;
    }];
}

Saya tidak tahu apakah ini cukup atau dianggap sebagai praktik multi-threading yang baik.

person mashers    schedule 25.03.2016
comment
Solusi di atas tampaknya berfungsi dengan baik. Menambahkan panggilan ke [NSObject cancelPreviousPerformRequestsWithTarget:self] sebelum [self performSelector:...] menyebabkan aplikasi menunggu hingga akhir operasi penyimpanan pertama dan kemudian menyimpan sekali lagi setelah selesai. Saya tetap menerima masukan apa pun tentang solusi ini. - person mashers; 25.03.2016