偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

weak的生命周期

移動開發(fā) iOS
我們都知道weak表示的是一個弱引用,這個引用不會增加對象的引用計數(shù),并且在所指向的對象被釋放之后,weak指針會被設(shè)置的為nil。weak引用通常是用于處理循環(huán)引用的問題,如代理及block的使用中,相對會較多的使用到weak。

weak的生命周期

我們都知道weak表示的是一個弱引用,這個引用不會增加對象的引用計數(shù),并且在所指向的對象被釋放之后,weak指針會被設(shè)置的為nil。weak引用通常是用于處理循環(huán)引用的問題,如代理及block的使用中,相對會較多的使用到weak。

之前對weak的實現(xiàn)略有了解,知道它的一個基本的生命周期,但具體是怎么實現(xiàn)的,了解得不是太清晰。今天又翻了翻《Objective-C高級編程》關(guān)于__weak的講解,在此做個筆記。

我們以下面這行代碼為例:

代碼清單1:示例代碼

  1. id __weak obj1 = obj; 

當(dāng)我們初始化一個weak變量時,runtime會調(diào)用objc_initWeak函數(shù)。這個函數(shù)在Clang中的聲明如下:

  1. id objc_initWeak(id *object, id value); 

其具體實現(xiàn)如下:

  1. id objc_initWeak(id *object, id value) 
  2. *object = 0
  3. return objc_storeWeak(object, value); 

示例代碼輪換成編譯器的模擬代碼如下:

  1. id obj1; 
  2. objc_initWeak(&obj1, obj); 

因此,這里所做的事是先將obj1初始化為0(nil),然后將obj1的地址及obj作為參數(shù)傳遞給objc_storeWeak函數(shù)。

objc_initWeak函數(shù)有一個前提條件:就是object必須是一個沒有被注冊為__weak對象的有效指針。而value則可以是null,或者指向一個有效的對象。

如果value是一個空指針或者其指向的對象已經(jīng)被釋放了,則object是zero-initialized的。否則,object將被注冊為一個指向value的__weak對象。而這事應(yīng)該是objc_storeWeak函數(shù)干的。objc_storeWeak的函數(shù)聲明如下:

  1. id objc_storeWeak(id *location, id value); 

其具體實現(xiàn)如下:

  1. id objc_storeWeak(id *location, id newObj) 
  2. id oldObj; 
  3. SideTable *oldTable; 
  4. SideTable *newTable; 
  5.  
  6. ...... 
  7.  
  8. // Acquire locks for old and new values. 
  9. // Order by lock address to prevent lock ordering problems. 
  10. // Retry if the old value changes underneath us. 
  11. retry: 
  12. oldObj = *location; 
  13.  
  14. oldTable = SideTable::tableForPointer(oldObj); 
  15. newTable = SideTable::tableForPointer(newObj); 
  16.  
  17. ...... 
  18.  
  19. if (*location != oldObj) { 
  20. OSSpinLockUnlock(lock1); 
  21. #if SIDE_TABLE_STRIPE > 1 
  22. if (lock1 != lock2) OSSpinLockUnlock(lock2); 
  23. #endif 
  24. goto retry; 
  25.  
  26. if (oldObj) { 
  27. weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); 
  28. if (newObj) { 
  29. newObj = weak_register_no_lock(&newTable->weak_table, newObj,location); 
  30. // weak_register_no_lock returns NULL if weak store should be rejected 
  31. // Do not set *location anywhere else. That would introduce a race. 
  32. *location = newObj; 
  33.  
  34. ...... 
  35.  
  36. return newObj; 

我們撇開源碼中各種鎖操作,來看看這段代碼都做了些什么。在此之前,我們先來了解下weak表和SideTable。

weak表是一個弱引用表,實現(xiàn)為一個weak_table_t結(jié)構(gòu)體,存儲了某個對象相關(guān)的的所有的弱引用信息。其定義如下(具體定義在objc-weak.h中):

  1. struct weak_table_t { 
  2. weak_entry_t *weak_entries; 
  3. size_t num_entries; 
  4. ...... 
  5. }; 

其中weak_entry_t是存儲在弱引用表中的一個內(nèi)部結(jié)構(gòu)體,它負(fù)責(zé)維護(hù)和存儲指向一個對象的所有弱引用hash表。其定義如下:

  1. struct weak_entry_t { 
  2. DisguisedPtr<objc_object> referent; 
  3. union { 
  4. struct { 
  5. weak_referrer_t *referrers; 
  6. uintptr_t out_of_line : 1
  7. ...... 
  8. }; 
  9. struct { 
  10. // out_of_line=0 is LSB of one of these (don't care which) 
  11. weak_referrer_t inline_referrers[WEAK_INLINE_COUNT]; 
  12. }; 
  13. }; 
  14. }; 

其中referent是被引用的對象,即示例代碼中的obj對象。下面的union即存儲了所有指向該對象的弱引用。由注釋可以看到,當(dāng)out_of_line等于0時,hash表被一個數(shù)組所代替。另外,所有的弱引用對象的地址都是存儲在weak_referrer_t指針的地址中。其定義如下:

typedef objc_object ** weak_referrer_t;

SideTable是一個用C++實現(xiàn)的類,它的具體定義在NSObject.mm中,我們來看看它的一些成員變量的定義:

  1. class SideTable { 
  2. private
  3. static uint8_t table_buf[SIDE_TABLE_STRIPE * SIDE_TABLE_SIZE]; 
  4.  
  5. public
  6.  
  7. RefcountMap refcnts; 
  8. weak_table_t weak_table; 
  9.  
  10. ...... 
  11.  

RefcountMap refcnts,大家應(yīng)該能猜到這個做什么用的吧?看著像是引用計數(shù)什么的。哈哈,貌似就是啊,這東東存儲了一個對象的引用計數(shù)的信息。當(dāng)然,我們在這里不去探究它,我們關(guān)注的是weak_table。這個成員變量指向的就是一個對象的weak表。

了解了weak表和SideTable,讓我們再回過頭來看看objc_storeWeak。首先是根據(jù)weak指針找到其指向的老的對象:

  1. oldObj = *location; 

然后獲取到與新舊對象相關(guān)的SideTable對象:

  1. oldTable = SideTable::tableForPointer(oldObj); 
  2. newTable = SideTable::tableForPointer(newObj); 
  3.  
  4. 下面要做的就是在老對象的weak表中移除指向信息,而在新對象的weak表中建立關(guān)聯(lián)信息: 
  5.  
  6. if (oldObj) { 
  7. weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); 
  8. if (newObj) { 
  9. newObj = weak_register_no_lock(&newTable->weak_table, newObj,location); 
  10. // weak_register_no_lock returns NULL if weak store should be rejected 

接下來讓弱引用指針指向新的對象:

  1. *location = newObj; 

***會返回這個新對象:

  1. return newObj; 

objc_storeWeak的基本實現(xiàn)就是這樣。當(dāng)然,在objc_initWeak中調(diào)用objc_storeWeak時,老對象是空的,所有不會執(zhí)行weak_unregister_no_lock操作。

而當(dāng)weak引用指向的對象被釋放時,又是如何去處理weak指針的呢?當(dāng)釋放對象時,其基本流程如下:

調(diào)用objc_release

因為對象的引用計數(shù)為0,所以執(zhí)行dealloc

在dealloc中,調(diào)用了_objc_rootDealloc函數(shù)

在_objc_rootDealloc中,調(diào)用了object_dispose函數(shù)

調(diào)用objc_destructInstance

***調(diào)用objc_clear_deallocating

我們重點關(guān)注一下***一步,objc_clear_deallocating的具體實現(xiàn)如下:

  1. void objc_clear_deallocating(id obj) 
  2. ...... 
  3.  
  4. SideTable *table = SideTable::tableForPointer(obj); 
  5.  
  6. // clear any weak table items 
  7. // clear extra retain count and deallocating bit 
  8. // (fixme warn or abort if extra retain count == 0 ?) 
  9. OSSpinLockLock(&table->slock); 
  10. if (seen_weak_refs) { 
  11. arr_clear_deallocating(&table->weak_table, obj); 
  12. ...... 

我們可以看到,在這個函數(shù)中,首先取出對象對應(yīng)的SideTable實例,如果這個對象有關(guān)聯(lián)的弱引用,則調(diào)用arr_clear_deallocating來清除對象的弱引用信息。我們來看看arr_clear_deallocating具體實現(xiàn):

  1. PRIVATE_EXTERN void arr_clear_deallocating(weak_table_t *weak_table, id referent) { 
  2. weak_entry_t *entry = weak_entry_for_referent(weak_table, referent); 
  3. if (entry == NULL) { 
  4. ...... 
  5. return
  6. // zero out references 
  7. for (int i = 0; i < entry->referrers.num_allocated; ++i) { 
  8. id *referrer = entry->referrers.refs[i].referrer; 
  9. if (referrer) { 
  10. if (*referrer == referent) { 
  11. *referrer = nil; 
  12. else if (*referrer) { 
  13. _objc_inform("__weak variable @ %p holds %p instead of %p\n", referrer, *referrer, referent); 
  14.  
  15. weak_entry_remove_no_lock(weak_table, entry); 
  16. weak_table->num_weak_refs--; 

這個函數(shù)首先是找出對象對應(yīng)的weak_entry_t鏈表,然后挨個將弱引用置為nil。***清理對象的記錄。

通過上面的描述,我們基本能了解一個weak引用從生到死的過程。從這個流程可以看出,一個weak引用的處理涉及各種查表、添加與刪除操作,還是有一定消耗的。所以如果大量使用__weak變量的話,會對性能造成一定的影響。那么,我們應(yīng)該在什么時候去使用weak呢?《Objective-C高級編程》給我們的建議是只在避免循環(huán)引用的時候使用__weak修飾符。

另外,在clang中,還提供了不少關(guān)于weak引用的處理函數(shù)。如objc_loadWeak, objc_destroyWeak, objc_moveWeak等,我們可以在蘋果的開源代碼中找到相關(guān)的實現(xiàn)。等有時間,我再好好研究研究。

參考

《Objective-C高級編程》1.4: __weak修飾符

Clang 3.7 documentation – Objective-C Automatic Reference Counting (ARC)

apple opensource – NSObject.mm

零碎

CAGradientLayer

CAGradientLayer類是用于在其背景色上繪制一個顏色漸變,以填充層的整個形狀,包括圓角。這個類繼承自CALayer類,使用起來還是很方便的。

與Quartz 2D中的漸變處理類似,一個漸變有一個起始位置(startPoint)和一個結(jié)束位置(endPoint),在這兩個位置之間,我們可以指定一組顏色值(colors,元素是CGColorRef對象),可以是兩個,也可以是多個,每個顏色值會對應(yīng)一個位置(locations)。另外,漸變還分為軸向漸變和徑向漸變。

我們寫個實例來看看CAGradientLayer的具體使用:

  1. CAGradientLayer *layer = [CAGradientLayer layer]; 
  2. layer.startPoint = (CGPoint){0.5f, 0.0f}; 
  3. layer.endPoint = (CGPoint){0.5f, 1.0f}; 
  4. layer.colors = [NSArray arrayWithObjects:(id)[UIColor blueColor].CGColor, (id)[UIColor redColor].CGColor, (id)[UIColor greenColor].CGColor, nil]; 
  5. layer.locations = @[@0.0f, @0.6f, @1.0f]; 
  6. layer.frame = self.view.layer.bounds; 
  7.  
  8. [self.view.layer insertSublayer:layer atIndex:0]; 

參考

CAGradientLayer Class Reference

Xcode中Ineligible Devices的處理

換了臺新電腦,裝了個Xcode 6.3,整了個新證書和profile,然后打開Xcode,連上手機(jī)。額,然后發(fā)現(xiàn)設(shè)備居然被標(biāo)識為Ineligible Devices,沒認(rèn)出來。情況類似于下圖:

電腦是受信任的,證書和profile也都是OK的。試了幾次重啟Xcode和重新連接手機(jī),無效。設(shè)備就是選不了。***是在Product->Destination里面才選中這個設(shè)備的。不過在工具欄還是不能選擇,郁悶,求解。

iOS 7后隱藏UITextField的光標(biāo)

新項目只支持iOS 7后,很多事情變得簡單多了,就像隱藏UITextField的光標(biāo)一樣,就簡單的一句話:

textFiled.tintColor = [UIColor clearColor];

通常我們用UIPickerView作為我們的UITextField的inputView時,我們是需要隱藏光標(biāo)的。當(dāng)然,如果想換個光標(biāo)顏色,也是這么處理。

這么處理的有個遺留問題是:通常我們使用UIPickerView作為UITextField的inputView時, 并不希望去執(zhí)行各種菜單操作(全選、復(fù)制、粘帖),但只是去設(shè)置UITextField的tintColor時,我們?nèi)匀豢梢詧?zhí)行這邊操作,所以需要加額外的處理。這個問題,我們可以這樣處理:在textFieldShouldBeginEditing:中,我們把UITextField的userInteractionEnabled設(shè)置為NO,然后在textFieldShouldEndEditing:,將將這個值設(shè)置回來。如下:

  1. - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { 
  2.  
  3. textField.userInteractionEnabled = NO; 
  4.  
  5. return YES; 
  6.  
  7. - (BOOL)textFieldShouldEndEditing:(UITextField *)textField { 
  8.  
  9. textField.userInteractionEnabled = YES; 
  10.  
  11. return YES; 

這樣就OK了。當(dāng)然這只是我們當(dāng)前使用的一種處理方式,還有其它的方法,直接google或者stackoverflow吧。

iOS 7后UIAlertView中文字左對齊問題

在iOS 7之前,如果我們想要讓UIAlertView中的文字居左顯示的話,可以使用以下這段代碼來處理:

  1. for (UIView *view in alert.subviews) { 
  2. if([[view class] isSubclassOfClass:[UILabel class]]) { 
  3. ((UILabel*)view).textAlignment = NSTextAlignmentLeft; 

但很遺憾的是,在iOS 7之后,蘋果不讓我們這么干了。我們?nèi)トIAlertView的subviews時,獲得的只是一個空數(shù)組,我們沒有辦法獲取到我們想要的label。怎么辦?三條路:告訴產(chǎn)品經(jīng)理和UED說這個實現(xiàn)不了(當(dāng)然,這個是會被鄙視的,人家會說你能力差);自己寫;找第三方開源代碼。嘿嘿,不過由于最近時間緊,所以我決定跟他們說實現(xiàn)不了,哈哈。不過在github上找了一個開源的,Custom iOS AlertView,star的數(shù)量也不少,看來不錯,回頭好好研究研究。

責(zé)任編輯:chenqingxiang 來源: 南峰子的技術(shù)博客
相關(guān)推薦

2022-04-19 07:20:24

軟件開發(fā)安全生命周期SSDLC應(yīng)用安全

2009-06-11 11:28:35

JSF生命周期

2010-07-14 10:48:37

Perl線程

2009-06-18 13:32:39

Java線程生命周期

2012-04-28 13:23:12

Java生命周期

2011-06-16 09:31:21

ActivityAndroid

2013-07-29 05:11:38

iOS開發(fā)iOS開發(fā)學(xué)習(xí)類的'生命周期'

2012-01-16 09:00:56

線程

2009-06-17 15:06:50

Hibernate實體

2019-10-16 10:50:13

Linux內(nèi)核測試

2012-06-20 10:29:16

敏捷開發(fā)

2009-06-24 10:47:55

JSF生命周期

2013-08-19 17:03:00

.Net生命周期對象

2021-07-19 05:52:29

網(wǎng)絡(luò)生命周期網(wǎng)絡(luò)框架

2010-07-14 10:59:15

Perl線程

2015-07-09 15:42:48

ios應(yīng)用生命周期

2013-06-18 10:48:41

OpenSUSEOpenSUSE 12

2021-02-14 00:39:57

機(jī)器學(xué)習(xí)技術(shù)人工智能

2024-01-08 22:08:48

Rust生命周期編程

2009-06-24 10:34:39

JSF生命周期JSF應(yīng)用程序
點贊
收藏

51CTO技術(shù)棧公眾號