Saya sedikit bingung tentang penggunaan blok di Objective-C. Saat ini saya menggunakan ARC dan saya memiliki cukup banyak blok di aplikasi saya, saat ini selalu mengacu pada self
referensi yang lemah. self
Mungkinkah itu penyebab blok-blok ini mempertahankan dan menjaganya agar tidak dapat dialokasikan kembali? Pertanyaannya adalah, haruskah saya selalu menggunakan weak
referensi self
di dalam blok?
-(void)handleNewerData:(NSArray *)arr
{
ProcessOperation *operation =
[[ProcessOperation alloc] initWithDataToProcess:arr
completion:^(NSMutableArray *rows) {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateFeed:arr rows:rows];
});
}];
[dataProcessQueue addOperation:operation];
}
ProcessOperation.h
@interface ProcessOperation : NSOperation
{
NSMutableArray *dataArr;
NSMutableArray *rowHeightsArr;
void (^callback)(NSMutableArray *rows);
}
ProcessOperation.m
-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{
if(self =[super init]){
dataArr = [NSMutableArray arrayWithArray:data];
rowHeightsArr = [NSMutableArray new];
callback = cb;
}
return self;
}
- (void)main {
@autoreleasepool {
...
callback(rowHeightsArr);
}
}
ios
iphone
objective-c
automatic-ref-counting
weak-references
the_critic
sumber
sumber
Jawaban:
Ini membantu untuk tidak fokus pada
strong
atauweak
bagian dari diskusi. Alih-alih fokus pada bagian siklus .Siklus penahanan adalah lingkaran yang terjadi ketika Objek A mempertahankan Objek B, dan Obyek B mempertahankan Objek A. Dalam situasi itu, jika salah satu objek dilepaskan:
Dengan demikian, kedua objek hanya akan berkeliaran di memori untuk kehidupan program meskipun mereka harus, jika semuanya bekerja dengan baik, tidak dapat dialokasikan kembali.
Jadi, yang kami khawatirkan adalah mempertahankan siklus , dan tidak ada apa-apa tentang blok di dalam dan dari diri mereka yang menciptakan siklus ini. Ini bukan masalah, misalnya:
Blok tetap
self
, tetapiself
tidak mempertahankan blok. Jika satu atau yang lainnya dilepaskan, tidak ada siklus yang dibuat dan semuanya akan dibatalkan alokasi sebagaimana mestinya.Di mana Anda mendapat masalah adalah sesuatu seperti:
Sekarang, objek Anda (
self
) memilikistrong
referensi eksplisit ke blok. Dan blok memiliki referensi kuat yang tersiratself
. Itu sebuah siklus, dan sekarang tidak ada objek yang akan dialokasikan dengan benar.Karena, dalam situasi seperti ini,
self
menurut definisi sudah memilikistrong
referensi ke blok, biasanya paling mudah untuk diselesaikan dengan membuat referensi yang secara eksplisit lemahself
untuk blok yang akan digunakan:Tapi ini seharusnya bukan pola default yang Anda ikuti ketika berhadapan dengan blok panggilan itu
self
! Ini seharusnya hanya digunakan untuk memutus siklus retensi antara diri dan blok. Jika Anda mengadopsi pola ini di mana-mana, Anda akan berisiko melewatkan blok ke sesuatu yang dieksekusi setelahself
dibatalkan alokasi.sumber
-setCompleteionBlockWithSuccess:failure:
metode Anda . Tetapi jikapaginator
dimiliki olehViewController
, dan blok-blok ini tidak dipanggil setelahViewController
akan dirilis, menggunakan__weak
referensi akan menjadi langkah aman (karenaself
memiliki hal yang memiliki blok, dan kemungkinan masih ada ketika blok menyebutnya meskipun mereka tidak mempertahankannya). Tapi itu banyak "jika". Ini benar-benar tergantung pada apa yang seharusnya dilakukan.MyObject
danSomeOtherObject
keduanya memiliki blok. Tetapi karena kembali referensi blok untukMyObject
adalahweak
, blok tidak sendiriMyObject
. Jadi sementara blok dijamin ada selama salah satuMyObject
atauSomeOtherObject
ada, tidak ada jaminan yangMyObject
akan ada selama blok itu ada.MyObject
dapat sepenuhnya dialokasikan dan, selamaSomeOtherObject
masih ada, blok akan tetap ada.Anda tidak harus selalu menggunakan referensi yang lemah. Jika blok Anda tidak dipertahankan, tetapi dieksekusi dan kemudian dibuang, Anda dapat menangkap diri dengan kuat, karena itu tidak akan membuat siklus mempertahankan. Dalam beberapa kasus, Anda bahkan ingin agar blok menahan diri sampai selesainya blok sehingga tidak membatalkan alokasi sebelum waktunya. Namun, jika Anda menangkap blok dengan kuat, dan di dalam diri menangkap, itu akan membuat siklus tetap.
sumber
Saya sangat setuju dengan @jemmons:
Untuk mengatasi masalah ini orang dapat mendefinisikan referensi yang kuat di bagian
weakSelf
dalam blok:sumber
->
), di mana Anda ingin memastikan Anda benar-benar mendapatkan referensi yang valid dan menahannya terus menerus di seluruh rangkaian operasi, misalnyaif ( strongSelf ) { /* several operations */ }
Seperti yang ditunjukkan Leo, kode yang Anda tambahkan ke pertanyaan Anda tidak akan menyarankan siklus referensi yang kuat (alias, pertahankan siklus). Salah satu masalah terkait operasi yang dapat menyebabkan siklus referensi yang kuat adalah jika operasi tidak dirilis. Walaupun cuplikan kode Anda menunjukkan bahwa Anda belum mendefinisikan operasi Anda bersamaan, tetapi jika Anda melakukannya, itu tidak akan dirilis jika Anda tidak pernah diposting
isFinished
, atau jika Anda memiliki dependensi melingkar, atau sesuatu seperti itu. Dan jika operasi tidak dirilis, pengontrol tampilan tidak akan dirilis juga. Saya akan menyarankan menambahkan breakpoint atauNSLog
dalamdealloc
metode operasi Anda dan mengkonfirmasi bahwa dipanggil.Kamu berkata:
Masalah siklus mempertahankan (siklus referensi kuat) yang terjadi dengan blok sama seperti masalah siklus mempertahankan yang Anda kenal. Blok akan mempertahankan referensi kuat ke objek apa pun yang muncul di dalam blok, dan itu tidak akan merilis referensi kuat sampai blok itu sendiri dilepaskan. Jadi, jika referensi blok
self
, atau bahkan hanya referensi variabel instanself
, yang akan mempertahankan referensi kuat untuk diri sendiri, itu tidak diselesaikan sampai blok dilepaskan (atau dalam kasus ini, sampaiNSOperation
subkelas dilepaskan.Untuk informasi lebih lanjut, lihat bagian Hindari Siklus Referensi Kuat ketika Mengambil bagian mandiri Pemrograman dengan Objective-C: Bekerja dengan dokumen Blok .
Jika view controller Anda masih belum dirilis, Anda hanya perlu mengidentifikasi di mana referensi kuat yang belum terselesaikan berada (dengan asumsi Anda mengonfirmasi bahwa
NSOperation
deallocated). Contoh umum adalah penggunaan pengulanganNSTimer
. Atau beberapa kebiasaandelegate
atau objek lain yang secara keliru mempertahankanstrong
referensi. Anda sering dapat menggunakan Instrumen untuk melacak di mana objek mendapatkan referensi kuat mereka, misalnya:Atau di Xcode 5:
sumber
Beberapa penjelasan mengabaikan kondisi tentang siklus penahan [Jika sekelompok objek dihubungkan oleh lingkaran hubungan yang kuat, mereka menjaga satu sama lain hidup meskipun tidak ada referensi kuat dari luar grup.] Untuk informasi lebih lanjut, baca dokumen
sumber
Ini adalah bagaimana Anda dapat menggunakan diri di dalam blok:
// memanggil blok
sumber