結尾在@property (nonatomic, strong) nsstring *name;
的情況下分別執行以下兩段**,會發生什麼?
//code 1
dispatch_queue_t queue =
dispatch_get_global_queue(0
,0);
for(
int i =
0; i <
1000
; i++))
;}//code 2
dispatch_queue_t queue =
dispatch_get_global_queue(0
,0);
for(
int i =
0; i <
1000
; i++))
;}
這裡涉及的知識點有
多執行緒安全
屬性修飾詞的定義nonautomic
自動釋放池autoreleasepool
runtime
執行時機制,以及nstagged pointer
mrc
下的set
方法寫法
結果是code 1
會發生崩潰,code 2
不會
崩潰資訊如下
* thread #3
, queue =
, stop reason = exc_bad_access (code=exc_i386_gpflt)
* frame #0
:0x000000011077f01b libobjc.a.dylib`objc_release +
11 frame #1
:0x00000001107804c7 libobjc.a.dylib`(anonymous namespace)
::autoreleasepoolpage:
:pop
(void*)
+795
frame #2
:0x000000011328d5eb libdispatch.dylib`_dispatch_last_resort_autorelease_pool_pop +
27 frame #3
:0x000000011329e4cc libdispatch.dylib`_dispatch_root_queue_drain +
1569
frame #4
:0x000000011329e9af libdispatch.dylib`_dispatch_worker_thread2 +
130 frame #5
:0x0000000113679169 libsystem_pthread.dylib`_pthread_wqthread +
1387
frame #6
:0x0000000113678be9 libsystem_pthread.dylib`start_wqthread +
13
下面分析原因:
由於是nonatomic
,即表示非原子
,set
和get
方法在多執行緒中不再安全,當然atomic
也無法完全保證其在多執行緒中讀寫的資料安全,atomic
只會保護set
和get
方法,這裡不再詳細闡述。
不安全在**呢?由於set
方法是這樣的,在mrc
下(mrc下**用於分析)
-
(void
)setname:
(nsstring *
)name
}//當多執行緒中多個執行緒同時執行這個方法時,有可能出現重複呼叫`release`的情況
//即某乙個時刻,_name的位址還未變化前提下,[_name release]; 呼叫了兩次
dispatch_async(queue, ^);
這個方法只是代表在佇列queue
非同步執行,不能保證其執行緒唯一性,你可以列印執行緒資訊來證實,即可能在多個執行緒中執行(從執行緒池中取),所以存在多執行緒問題。
dispatch_async(queue, ^);
會將建立的變數加入到自動釋放池中,**其實就相當於這樣
//code 1
dispatch_queue_t queue =
dispatch_get_global_queue(0
,0);
for(
int i =
0; i <
1000
; i++))
;}
崩潰的原因,當某一時刻變數從autoreleasepool
中pop
時,會呼叫objc_release()
方法將其釋放(參考文章),此時可能存在_name
變數重複釋放,已經是壞記憶體了,從而崩潰。
也可以認為是多個執行緒執行了[_name release];
導致了崩潰。
//code 2
dispatch_queue_t queue =
dispatch_get_global_queue(0
,0);
for(
int i =
0; i <
1000
; i++))
;}
[nsstring stringwithformat:@"abc"];
是相對於生成了乙個nstagged pointer
,見參考文章 末尾有說明,由runtime
知識,objc_msgsend
內部會判斷是不是普通的指標,如果使用了tagged pointer
技術,就不是乙個oc物件,會從指標中直接進行取值,而不會進入訊息機制,做相應的記憶體管理**的呼叫.
在object_msgsend
的彙編**中,我們常常會看到tagged point
型別的判斷,如下段**
end_entry _objc_msgsend
entry _objc_msglookup
unwind _objc_msglookup, noframe
cmp x0, #0
// nil check and tagged pointer check
b.le llookup_nilortagged // (msb tagged pointer looks negative)
ldr x13,
[x0]
// x13 = isa
and x16, x13, #isa_mask // x16 = class
llookup_getisadone:
cachelookup lookup // returns imp
llookup_nilortagged:
b.eq llookup_nil // nil check
// tagged
mov x10, #0xf000000000000000
cmp x0, x10
b.hs llookup_exttag
adrp x10, _objc_debug_taggedpointer_classes@page
add x10, x10, _objc_debug_taggedpointer_classes@pageoff
ubfx x11, x0, #60
, #4
ldr x16,
[x10, x11, lsl #3
] b llookup_getisadone
llookup_exttag:
adrp x10, _objc_debug_taggedpointer_ext_classes@page
add x10, x10, _objc_debug_taggedpointer_ext_classes@pageoff
ubfx x11, x0, #52
, #8
ldr x16,
[x10, x11, lsl #3
] b llookup_getisadone
_objc_debug_taggedpointer_classes
實現如下
.globl _objc_debug_taggedpointer_classes
_objc_debug_taggedpointer_classes:
.fill 16,8
,0.globl _objc_debug_taggedpointer_ext_classes
既然不會走set
方法,那麼就不會涉及多執行緒安全問題。
將屬性修飾改為automic
或者對賦值操作加鎖,都是解決多執行緒下安全問題的方案之一。
記性不好是硬傷,所以我決定記下來,寫寫寫!
IOS開發 我的第乙個IOS程式
學完前面的objc基礎,那麼接下來我可以開始我的ios開發之旅了 1.首先開啟xcode建立乙個工程 3.在專案檔案區選擇viewcontroller.xib檔案 再選擇子螢幕object下的view,這樣就能開啟我們的iphone的窗體介面 4.接著在xcode主介面右下方拉入label butt...
iOS應用開發入門(1) 第乙個iOS應用
最近因為工作的原因,需要學習ios應用開發。本人現在在公司負責的是智慧型裝置聯網模組,所謂的智慧型裝置聯網,就是讓一些智慧型裝置 多半是沒用螢幕的裝置 連上wifi,因為沒有螢幕,所以無法像手機和平板那樣通過螢幕選擇wifi和輸入wifi密碼,這個時候就需要手機來輔助,將手機上的wifi資訊同步到智...
培養iOS開發新人的乙個思路
堅持兩個方 1 發現問題的方法 熟悉 的過程 1 照著乙個完整的工程,從最基本的頁面開始做起。不懂的地方就問,就查。2 在閱讀 或拿到需求後要學會對問題進行分解。乙個陌生的問題如果不能被分解,那麼它也很難被解決。3 根據分解出來的小任務,使用方法2進行解決。2 解決問題的方法 1 發現問題 一般是x...