這篇文章為您講述IOS深化學習之Weak關鍵字引見的闡明,詳細操作請看面的內容
前言從大二的開端接觸OC就用到了weak屬性修飾詞,但是事先只是知道如何去用這個關鍵字:避免循環援用。基本沒有深化地去理解它。 在剛來北京的時分面試進程中也經常考到該知識點。大點的公司能夠會問它如何運用?如何在對象銷毀後將對象置nil,小點的公司能夠只問一下它的運用。 Now,假如你對它發生恐懼或許已經對它發生過恐懼(+1),假如你被該關鍵字弄得整天吃不下飯,睡不著覺,那麼可以持續往下閱讀,希望讀過該博客之後可以幫到你。 廢話不多說,開端引見。
由淺入深先來看看最復雜的一個例子:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong)id strongPoint;
@property (nonatomic,weak)id weakPoint;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// self.strongPoint = [NSDate date];
self.strongPoint = [[UILabel alloc] init];
self.weakPoint = self.strongPoint;
self.strongPoint = nil;
NSLog(@"result is :%@", self.weakPoint);
}
@end
我們可以看到此時輸入的後果為:
2017-02-07 13:20:41.119278 Test[7341:2187477] result is :(null)
假如我們運用的strong來修飾weakPoint,此時輸入的後果為:
2017-02-07 13:23:13.211164 Test[7344:2187993] result is :<UILabel: 0x100206070; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x17009a590>>
假如我們運用assign來修飾weakPoint,此時運轉順序能夠會解體(由於假如援用操作發作時內存還沒有改動內容,照舊可以輸入正確後果,假如援用的時分內存內容發作改動了,就會crash),由於當assign指針所指向的內存被釋放之後,不會自動賦值為nil,這樣再次援用該指針的時分就會招致野指針操作。 對上述代碼運轉後果停止剖析: 當運用weak關鍵字的時分,不會添加對象的計數,而且當所指對象置nil的時分,運用weak修飾的指針將被賦值為nil; 當運用strong關鍵字的時分,會添加對象的計數,也就是說會堅持對象值的存在,所以當運用strong的時分weakPoint還會有值。 因而,我們從這裡可以得出一個後果: strong是強援用,它會堅持對象值的存在; weak是弱援用,當weak指針指向的對象摧毀之後,屬性值也會清空(nil out)。 (留意:運用 _ _ weak修飾 和在@ property外面設置weak是一樣的) 但是當我們執行如下代碼的時分:
__strong NSString *yourString = @"Your String";
__weak NSString *myString = yourString;
yourString = nil;
__unsafe_unretained NSString *theirString = myString;
NSLog(@"%p %@", yourString, yourString);
NSLog(@"%p %@", myString, myString);
NSLog(@"%p %@", theirString, theirString);
你會發現只要yourString為空,其他兩個都不為空,這個是為什麼呢?緣由如下
這裡是由於字符字面值永遠不會被釋放,所以你的weak指針還是指向它。 當你運用@""創立一個string對象的時分,它就是一個字面值,永遠不會被改動。假如你在順序中很多中央都用到了一樣的字符串,那麼你可以測試一下,它們都是同一個對象(地址一樣),String字面值不會銷毀。運用[[NSString alloc] initWithString:@"literal string"]也是一樣的效果。由於它指向了一個字面值的string。
那麼請問weak指針指向對象被回收的時分該指針是如何被自動置為nil的呢??
首先,大家可以看一下博客最前面的附錄,外面有兩個文檔,嚴厲來說是Apple的opensouce。外面有一個objc-weak的類。這裡是一個objc-weak.h類和一個objc-weak.mm類。
擴展知識
.m和.mm的區別
.m:源代碼文件,這個典型的源代碼文件擴展名,可以包括OC和C代碼。
.mm:源代碼文件,帶有這種擴展名的源代碼文件,除了可以包括OC和C代碼之外,還可以包括C++代碼。僅在你的OC代碼中的確需求運用C++類或許特性的時分才用這種擴展名。
從.h中可以看到以下幾個關鍵的兩個構造體:weak_entry_t和weak_table_t,以及一些辦法。接上去復雜引見一下weak如何自動置為nil。 weak的完成其實是一個weak表,該表是一個由自旋鎖管理的哈希表。 以下是從NSObject.mm外面摘出的一些辦法:
id
objc_initWeak(id *location, id newObj)
{
if (!newObj) {
*location = nil;
return nil;
}
return storeWeak<false/*old*/, true/*new*/, true/*crash*/>
(location, (objc_object*)newObj);
}
該function的作用是初始化一個新的weak指針指向對象的地址。其中的參數引見如下:
location段:_ _ weak指針的地址 newObj:對象的指針地址這裡調用的storeWeak辦法,storeWeak辦法外面經過template模板的參數停止更新weak操作,看源碼可以知道外面會調用weak_register_no_lock/weak_unregister_no_lock等objc-weak.mm外面的辦法停止相應的操作。objc-weak.h外面有句話:
For ARR, we also keep track of whether an arbitrary object is being
deallocated by briefly placing it in the table just prior to invoking
dealloc, and removing it via objc_clear_deallocating just prior to memory
reclamation.
對象被廢棄時最後調用objc_clear_deallocating。該函數完成如下:
void
objc_clear_deallocating(id obj)
{
assert(obj);
assert(!UseGC);
if (obj->isTaggedPointer()) return;
obj->clearDeallocating();
}
也就是調用了clearDeallocating,持續追蹤可以發現,它最終是運用了迭代器來取weak表的value,然後調用weak_clear_no_lock,然後查找對應的value,將該weak指針置空:
/**
* Called by dealloc; nils out all weak pointers that point to the
* provided object so that they can no longer be used.
*
* @param weak_table
* @param referent The object being deallocated.
*/
void
weak_clear_no_lock(weak_table_t *weak_table, id referent_id)
{
objc_object *referent = (objc_object *)referent_id;
weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
if (entry == nil) {
/// XXX shouldn't happen, but does with mismatched CF/objc
//printf("XXX no entry for clear deallocating %p\n", referent);
return;
}
// zero out references
weak_referrer_t *referrers;
size_t count;
if (entry->out_of_line) {
referrers = entry->referrers;
count = TABLE_SIZE(entry);
}
else {
referrers = entry->inline_referrers;
count = WEAK_INLINE_COUNT;
}
for (size_t i = 0; i < count; ++i) {
objc_object **referrer = referrers[i];
if (referrer) {
if (*referrer == referent) {
*referrer = nil;
}
else if (*referrer) {
_objc_inform("__weak variable at %p holds %p instead of %p. "
"This is probably incorrect use of "
"objc_storeWeak() and objc_loadWeak(). "
"Break on objc_weak_error to debug.\n",
referrer, (void*)*referrer, (void*)referent);
objc_weak_error();
}
}
}
weak_entry_remove(weak_table, entry);
}
objc_clear_deallocating該函數的舉措如下:
從weak表中獲取廢棄對象的地址為鍵值的記載 將包括在記載中的一切附有 _ _ weak修飾符變量的地址,賦值為nil 將weak表中刪除該記載 從援用計數表中刪除廢棄對象的地址為鍵值的記載 看了objc-weak.mm的源碼大約理解了:其實Weak表示一個hash表,然後外面的key是指向對象的地址,Value是Weak指針的地址的數組。 完畢以上便是我團體對weak的了解,檢查objc4的源碼,發現外面更多的都是構造體、構造體套構造體等等。
附錄 Apple的opensource。 Apple的github。 stackoverflow。 原文鏈接點此。
以上就是這篇文章的全部內容了,希望大家可以喜歡。
【iOS深化學習之Weak關鍵字引見】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!