performSelector的具體用法

BetterDays發表於2018-06-21

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
複製程式碼

相關文章