做爲一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是一個個人iOS交流羣:638302184,無論你是小白仍是大牛歡迎入駐 ,分享BAT,阿里面試題、面試經驗,討論技術, 與2800+iOS開發者一塊兒交流學習成長!
NSString * str1 = @"copyStr"; NSMutableString *str2 = [str1 copy]; NSMutableString *str3 = [str1 mutableCopy]; NSLog(@"str1:%p--%@",str1,str1); NSLog(@"str1:%p--%@",str2,str2); NSLog(@"str1:%p--%@",str3,str3);
2018-04-14 14:50:54.117652+0800 MutyCopy-Copy[2644:63575] str1:0x109a48068--copyStr 2018-04-14 14:50:54.117885+0800 MutyCopy-Copy[2644:63575] str1:0x109a48068--copyStr 2018-04-14 14:50:54.118010+0800 MutyCopy-Copy[2644:63575] str1:0x600000259a40--copyStr
1.str1,str2地址相同,而Str3地址不一樣
2.NSString的copy是淺拷貝,copy返回的對象是不可變對象
3.mutablecopy是深拷貝web
*案例二:面試
NSMutableString * str1 = [NSMutableString stringWithString:@"mutableStr"]; NSMutableString * str2 = [str1 copy]; NSMutableString * str3 = [str1 mutableCopy]; NSLog(@"str:%p-----%@",str1,str1); NSLog(@"str:%p-----%@",str2,str2); NSLog(@"str:%p-----%@",str3,str3);
2018-04-14 15:04:50.092820+0800 MutyCopy-Copy[2685:70866] str:0x60000025b210-----mutableStr 2018-04-14 15:04:50.093059+0800 MutyCopy-Copy[2685:70866] str:0x60000022ca40-----mutableStr 2018-04-14 15:04:50.093217+0800 MutyCopy-Copy[2685:70866] str:0x60000025b540-----mutableStr
1.str1,str2,str3地址都不一樣
2.NSMutableString對象copy與mutableCopy都是深拷貝
3.copy返回的對象是不可變對象編程
好比,咱們同時開啓2條線程下載文件A,文件B.設計模式
注意:若是線程很是很是多,會發生什麼狀況?
cpu會在多個多線程之間進行調度,消耗大量的CPU資源.這樣的話,每條線程被調度執行的頻次會下降,線程執行效率下降.
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadFun) object:nil]; [thread start];
線程一啓動,就會告訴CPU準別就緒,能夠隨時接受CPU調度.CPU調度當前線程以後,就會在線程thread中執行self的run方法安全
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
隱式建立並啓動線程服務器
[self performSelectorInBackground:@selector(run) withObject:nil];
1.啓動線程,start.就緒狀態-->>運行狀態.當新廠任務執行完畢,自動進入死亡狀態
2.阻塞(暫停)線程,進入阻塞狀態網絡
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
3.強制中止線程
進入死亡狀態多線程
注意:一旦線程中止了,就不能再次開啓任務.
若是,多個線程訪問同一塊資源的話,會形成數據錯亂的.
咱們應該怎麼解決呢?併發
3.如圖,
線程A和線程B同時訪問資源變量Integer,
爲了防止搶奪資源,
線程A在讀取資源變量Integer以前先加一把鎖,
而後讀取Integer的數據並在線程A中完成數據操做(17+1=18),
而後把數據寫入Integer中,
最後開鎖Unlock.在線程A對Integer操做的過程當中,
線程B是無權訪問Integer的,
只有線程A_Unlock後,線程B才能夠訪問資源變量Integer.
4.互斥鎖使用格式
@synchronized(self){//須要鎖定的代碼}異步
注意: 鎖定1分代碼只用1把鎖,用多把鎖是無效的
5.互斥鎖的優缺點
互斥鎖的使用前提:多條線程搶奪同一塊資源
優勢:能有效防止因多線程搶奪資源形成的數據安全問題
缺點:須要消耗大量的CPU
6.nonatomic和atomic
atomic:
原子屬性,爲setter方法加鎖(默認就是atomic)
線程安全,須要消耗大量的資源
nonatomic:
非原子屬性,不會爲setter方法加鎖
非線程安全,適合內存小的移動設備
1.執行任務
GCD中有2個用來執行任務的函數
1.1用同步的方式執行任務
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); queue:隊列 block:任務
1.2用異步的方式執行任務
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
1.3同步和異步的區別
同步:只能在當前線程中執行任務,不具有開啓新線程的能力
異步:能夠再新的線程中執行任務,具有開啓新線程的能力
注意: 同步函數 + 主隊列 == 死鎖
dispatch_queue_t dispatch_get_global_queue( dispatch_queue_priority_t priority, 隊列的優先級 unsigned long flags);
全局併發隊列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t = dispatch_queue_create(const char*label, 隊列名稱 dispatch_queue_attr_t attr); 隊列屬性,通常用NULL便可
2.使用主隊列
放在主隊列中的任務,都會放到主線程中執行
使用dispatch_get_main_queue()得到主隊列
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 執行耗時的異步操做... dispatch_async(dispatch_get_main_queue(), ^{ 回到主線程,執行UI刷新操做 }); });
設定好延遲的時間後,它會先執行後邊的代碼,2秒後再調用self的run方法(而且不會卡主線程,在主線程調最後會回到主線程,在子線程調最後會回到子線程)
withObject:參數 afterDelay:延遲的時間 [self performSelector:@selector(run) withObject:nil afterDelay:2.0];
使用GCD函數(2秒後自動開啓新線程 執行block中的代碼,不會卡主當前的線程,在主/子線程調用均可以使用)
DISPATCH_TIME_NOW:如今開始的意 2.0 * NSEC_PER_SEC:設置的秒數(直接更改數字便可) dispatch_get_main_queue():主隊列的意思 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 2秒後執行這裏的代碼... 在哪一個線程執行,跟隊列類型有關 });
3.會卡住主線程
[NSThread sleepForTimeInterval:3]
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ 程序運行過程當中,永遠只執行1次的代碼(這裏面默認是線程安全的) });
dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 執行1個耗時的異步操做 }); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 執行1個耗時的異步操做 }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 等前面的異步操做都執行完畢後,回到主線程... });
1.異步函數+併發隊列
1.建立隊列(併發隊列) dispatch_queue_t queue = dispatch_queue_create("com.baidu.www", DISPATCH_QUEUE_CONCURRENT); 異步函數 dispatch_async(queue, ^{ NSLog(@"1---%@",[NSThread currentThread]); });
2.異步函數+串行隊列
1.建立隊列(串行隊列) dispatch_queue_t queue = dispatch_queue_create("com.baidu.www", DISPATCH_QUEUE_SERIAL); 異步函數 dispatch_async(queue, ^{ NSLog(@"1---%@",[NSThread currentThread]); });
3.同步函數+串行隊列
1.建立隊列(串行隊列) dispatch_queue_t queue = dispatch_queue_create("com.baidu.www", DISPATCH_QUEUE_SERIAL); 同步函數 dispatch_sync(queue, ^{ NSLog(@"1---%@",[NSThread currentThread]); });
4.同步函數+併發隊列
//得到全局併發隊列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 同步函數 dispatch_sync(queue, ^{ NSLog(@"1---%@",[NSThread currentThread]); });
5.異步函數+主隊列
1.得到主隊列 dispatch_queue_t queue = dispatch_get_main_queue(); 異步函數 dispatch_async(queue, ^{ NSLog(@"1---%@",[NSThread currentThread]); });
6.同步函數+主隊列
1.得到主隊列 dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_sync(queue, ^{ NSLog(@"1---%@",[NSThread currentThread]); });
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
2.調用start方法開始執行操做
- (void)start;
一旦執行操做,就會調用target的sel方法
默認狀況下,調用了start方法後並不會開一條新線程去執行操做,而是在當前線程同步執行操做;只有將NSOperation放到一個NSOperationQueue中,纔會異步執行操做
+ (id)blockOperationWithBlock:(void (^)(void))block;
經過addExecutionBlock:方法添加更多的操做
- (void)addExecutionBlock:(void (^)(void))block;
只要NSBlockOperation封裝的操做數 > 1,就會異步執行操做
- (void)addOperation:(NSOperation *)operation; - (void)addOperationWithBlock:(void (^)(void))block;
-(NSInteger)maxConcurrentOperationCount; - (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
int main(int argc, char * argv[]) { NSLog(@"main"); return 0; }
int main(int argc, char * argv[]) { BOOL run = YES; do{ //執行各類任務,處理各類事件 }while(run); return 0; }
int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
Core Foundation中關於RunLoop的5個類:
CFRunLoopRef:它本身,也就表明一個RunLoop對象
CFRunLoopModeRef:RunLoop的運行模式
CFRunLoopSourceRef:事件源
CFRunLoopTimerRef:時間的觸發器
CFRunLoopbaserverRef:觀察者 監聽CFRunLoopRef的狀態
1.通知觀察者,即將進入Loop
2.通知觀察者,將要處理定時器
3.通知觀察者,將要處理非基於端口的源
4.處理非基於端口的源
5.若是有基於端口的源準備好並處於等待狀態,當即啓動,跳到第9步
6.通知觀察者,線程即將休眠
7.休眠,等待喚醒
8.通知觀察者,線程剛被喚醒
9.處理喚醒時收到的消息,以後跳到第2步
10.通知觀察者,即將推出Loop
HTTP協議規定:1個完整的由客戶端發給服務器的HTTP請求中包含如下內容
文章來源於網絡,若有侵權,請聯繫小編刪除。