performSelector
具體的建立方式有10種,根據執行方式分為了五大類。
//1️⃣三種 這三種跟直接呼叫方法沒有區別,同步執行任務,阻塞當前執行緒。執行完sel再繼續執行原來任務
[self performSelector:sel];
[self performSelector:sel withObject:nil];
[self performSelector:sel withObject:nil withObject:nil];
//2️⃣兩種 延時執行、不阻塞當前執行緒
[self performSelector:sel withObject:nil afterDelay:1];
NSArray *array;
[self performSelector:sel withObject:nil afterDelay:1 inModes:array];
//3️⃣兩種 子執行緒主執行緒均可呼叫,任務在主執行緒執行,主要用來更新UI
[self performSelectorOnMainThread:sel withObject:nil waitUntilDone:YES];
[self performSelectorOnMainThread:sel withObject:nil waitUntilDone:YES modes:array];
//4️⃣一種 開啟子執行緒執行方法
[self performSelectorInBackground:sel withObject:nil];
//5️⃣兩種 指定某個執行緒執行方法 YES:阻塞當前執行緒 NO:不阻塞當前執行緒
NSThread *thread;
[self performSelector:sel onThread:thread withObject:nil waitUntilDone:YES];
[self performSelector:sel onThread:thread withObject:nil waitUntilDone:YES modes:array];
複製程式碼
延時執行解決記憶體洩漏的方法:
執行 [self performSelector:sel withObject:self afterDelay:1];
的時候,系統會將self的引用計數加1,執行完這個方法時,還會將self的引用計數減1,當方法還沒有執行的時候,要返回父檢視釋放當前檢視的時候,self
的計數沒有減少到0,而導致無法呼叫dealloc
方法,出現了記憶體洩露。
所以最後我的解決辦法就是取消那些還沒有來得及執行的延時函式:
[NSObject cancelPreviousPerformRequestsWithTarget:self]
當然你也可以一個一個得這樣用:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(method1:) object:nil]
1️⃣、正常執行方法,不阻塞當前執行緒
//三種 這三種跟直接呼叫方法沒有區別,同步執行任務,阻塞當前執行緒。執行完sel再繼續執行原來任務
[self performSelector:sel];
[self performSelector:sel withObject:nil];
[self performSelector:sel withObject:nil withObject:nil];
複製程式碼
- (void)threadTest{
NSLog(@"1");
SEL sel = @selector(getCurrentThread);
[self performSelector:sel];
NSLog(@"2");
}
- (void)getCurrentThread{
NSThread *currentThread = [NSThread currentThread];
NSLog(@"currentThread == %@",currentThread);
NSLog(@"3");
}
複製程式碼
2018-06-21 14:58:30.168231+0800 WLZCyclycReference[27474:256398] 1
2018-06-21 14:58:30.168399+0800 WLZCyclycReference[27474:256398] currentThread == <NSThread: 0x60c00006a5c0>{number = 1, name = main}
2018-06-21 14:58:30.168481+0800 WLZCyclycReference[27474:256398] 3
2018-06-21 14:58:30.168573+0800 WLZCyclycReference[27474:256398] 2
複製程式碼
2️⃣、延時執行,非同步執行,不阻塞當前執行緒。只能在主執行緒執行。
//兩種 延時執行、不阻塞當前執行緒
[self performSelector:sel withObject:nil afterDelay:1];
NSArray *array;
[self performSelector:sel withObject:nil afterDelay:1 inModes:array];
複製程式碼
- (void)threadTest{
NSLog(@"1");
SEL sel = @selector(getCurrentThread);
[self performSelector:sel withObject:nil afterDelay:1];
NSLog(@"2");
}
- (void)getCurrentThread{
NSThread *currentThread = [NSThread currentThread];
NSLog(@"currentThread == %@",currentThread);
NSLog(@"3");
}
複製程式碼
2018-06-21 15:01:28.122273+0800 WLZCyclycReference[27533:259144] 1
2018-06-21 15:01:28.122422+0800 WLZCyclycReference[27533:259144] 2
2018-06-21 15:01:29.122463+0800 WLZCyclycReference[27533:259144] currentThread == <NSThread: 0x604000071300>{number = 1, name = main}
2018-06-21 15:01:29.122664+0800 WLZCyclycReference[27533:259144] 3
複製程式碼
3️⃣、子執行緒主執行緒均可呼叫,任務在主執行緒執行,主要用來更新UI
//兩種 在主執行緒執行 YES:阻塞主執行緒 NO:不阻塞主執行緒
[self performSelectorOnMainThread:sel withObject:nil waitUntilDone:YES];
[self performSelectorOnMainThread:sel withObject:nil waitUntilDone:YES modes:array];
複製程式碼
- (void)threadTest{
NSLog(@"1");
SEL sel = @selector(getCurrentThread);
dispatch_queue_t queue = dispatch_queue_create("com.apple.www", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
[self performSelectorOnMainThread:sel withObject:nil waitUntilDone:YES];
});
NSLog(@"2");
}
- (void)getCurrentThread{
//回到主執行緒更新UI
NSLog(@"3");
}
複製程式碼
你期望的情況是不是 132,但是事實輸出的是123,這是因為queue在開啟子執行緒執行
performSelectorOnMainThread
方法的過程中,NSLog(@"2");
已經執行完了,如果想要得到理想的結果,那麼你就要在主執行緒中放足夠多的耗時任務,保證子執行緒執行到performSelectorOnMainThread
方法的時候,主執行緒的任務還沒執行完,醬紫才會出現阻塞主執行緒的情況。
4️⃣、開啟子執行緒
這就沒什麼好說的了,開個子執行緒而已
//一種 開啟子執行緒執行方法
[self performSelectorInBackground:sel withObject:nil];
複製程式碼
- (void)threadTest{
NSLog(@"1");
SEL sel = @selector(getCurrentThread);
[self performSelectorInBackground:sel withObject:nil];
NSLog(@"2");
}
- (void)getCurrentThread{
NSThread *currentThread = [NSThread currentThread];
NSLog(@"currentThread == %@",currentThread);
NSLog(@"3");
}
2018-06-21 15:28:40.007851+0800 WLZCyclycReference[28121:284079] 1
2018-06-21 15:28:40.008061+0800 WLZCyclycReference[28121:284079] 2
2018-06-21 15:28:40.008270+0800 WLZCyclycReference[28121:284165] currentThread == <NSThread: 0x60c000078840>{number = 3, name = (null)}
2018-06-21 15:28:40.008428+0800 WLZCyclycReference[28121:284165] 3
複製程式碼
5️⃣、指定某個執行緒執行方法
//兩種 指定某個執行緒執行方法 YES:阻塞當前執行緒 NO:不阻塞當前執行緒
NSThread *thread;
[self performSelector:sel onThread:thread withObject:nil waitUntilDone:YES];
[self performSelector:sel onThread:thread withObject:nil waitUntilDone:YES modes:array];
複製程式碼
- (void)threadTest{
NSLog(@"1");
SEL sel = @selector(getCurrentThread);
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(createThread) object:nil];
[thread start];
[self performSelector:sel onThread:thread withObject:nil waitUntilDone:NO];
NSLog(@"2");
}
- (void)getCurrentThread{
NSThread *currentThread = [NSThread currentThread];
NSLog(@"currentThread == %@",currentThread);
NSLog(@"3");
}
- (void)createThread{
//建立執行緒記得開啟runloop
[[NSRunLoop currentRunLoop] run];
}
2018-06-21 15:52:08.413852+0800 WLZCyclycReference[28657:307146] 1
2018-06-21 15:52:08.414072+0800 WLZCyclycReference[28657:307146] 2
2018-06-21 15:52:08.414208+0800 WLZCyclycReference[28657:307230] currentThread == <NSThread: 0x6000002606c0>{number = 3, name = (null)}
2018-06-21 15:52:08.414307+0800 WLZCyclycReference[28657:307230] 3
複製程式碼