__strong 및weak의 용도

4002 단어

배경.


iOS의 일상적인 개발에서 Block을 사용할 때 변수를 __weak로 명시하여 순환 인용을 방지해야 한다.그런데 Block 내부에서 왜 다시 __strong라고 성명했습니까?

예제

Don't BB, show me the code. 프로그램원으로서 코드를 직접 올리는 것이 직관적이고 이해하기 쉽다.
  • eg1, 단순 사용__weak의 단점:
  • @interface MyObject : NSObject
    @end
    
    @implementation MyObject
    - (void)dealloc {
        NSLog(@"MyObject dealloc");
    }
    @end
    
    
    - (IBAction)buttonClickedWeak:(id)sender {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            MyObject *obj = [[MyObject alloc] init];
            
            __weak typeof(obj) weakObj = obj;
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                NSLog(@"GCD--sleepBefore obj:%@",weakObj);
                sleep(3);
                NSLog(@"GCD--sleepAfter obj:%@",weakObj);
            });
            sleep(1);
            obj = nil;
            NSLog(@"    nil");
        });
    }
    

    위에서 보여준 코드와 같이 시청자 여러분은 먼저 컨트롤러 출력의log가 어떤 것인지 분석하고 실제 결과와 같은지 확인할 수 있습니다.
    다음은 실제 로그 출력입니다.
     GCD--sleepBefore obj:
     MyObject dealloc
         nil
     GCD--sleepAfter obj:(null)
    

    여기서 우리는 첫 번째 병렬 대기열을 대기열 A, 두 번째 대기열 B라고 부른다. 분명히 대기열 Asleep이 있을 때 대기열 B는 이미 첫 번째 줄log까지 실행되었기 때문에 여기GCD--sleepBefore의 로그는obj를 정상적으로 출력할 수 있다.따라서 대기열 A가 깨어나고 obj가 nil로 설정되어 풀려납니다.그래서 대기열 B가 3초 동안 깨어난 후GCD--sleepAfter의log가 인쇄된obj는null이다.
  • eg2, 연합사용__weak__strong:
  • - (IBAction)buttonclicked2:(id)sender {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            MyObject *obj = [[MyObject alloc] init];
            
            __weak typeof(obj) weakObj = obj;
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                __strong typeof(weakObj) strongObj = weakObj;
                sleep(3);
                NSLog(@"GCD--obj:%@",strongObj);
            });
            obj = nil;
            NSLog(@"    nil");
        });
    }
    

    이번에 Block 내부에서obj를 강제로 인용했는데 대기열 B3s가 깨어난 후에 정확한 출력을 할 수 있을까요?
    다음은 실제 로그 출력입니다.
     MyObject dealloc
         nil
     GCD--obj:(null)
    

    우리는 여전히 정확하게 출력할 수 없다는 것을 보았다. 이는 Block 내부 성명__strong은 대상이 Block 내부에서 강제로 인용되는 것을 보장할 수 있을 뿐이다. 즉, Block 실행 과정에서 방출되지 않기 때문이다. 그러나 Block을 실행할 때 대상이 방출되고 성명__strong도 이 문제를 해결할 수 없기 때문이다.위에서 보여준 코드는 Block이 인용한 외부 변수weakObj__weak로 성명되었기 때문에 Block은obj를 강제로 인용하지 않기 때문에obj가 부여된값은nil로 바로 분석 함수를 촉발하여obj를 방출한다.그래서 Block 내부에 있는 __strong typeof(weakObj) strongObj = weakObj;라는 문장을 집행할 때 실제로는 __strong typeof(weakObj) strongObj = nil;에 해당한다
  • eg3, 연합사용__weak__strong:
  • - (IBAction)buttonclicked:(id)sender {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            MyObject *obj = [[MyObject alloc] init];
            __weak typeof(obj) weakObj = obj;
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                __strong typeof(weakObj) strongObj = weakObj;
                sleep(3);
                NSLog(@"GCD--obj:%@",strongObj);
            });
            sleep(1);
            obj = nil;
            NSLog(@"    nil");
        });
    }
    

    이번에 나는obj부치nil를 하기 전에 대기열 Asleep를 1초 동안 대기열 B에 들어갈 때obj가 풀리지 않도록 했다. 대기열 B 3s가 깨어난 후에 정확한 출력을 할 수 있을까?
    다음은 실제 로그 출력입니다.
         nil
     GCD--obj:
     MyObject dealloc
    

    이번에 정상적으로 출력되었습니다. 이것은 obj부치nil 이전에 대열 B의 __strong 성명을 실행했기 때문입니다. 이때 obj는 Block에 의해 강제로 인용됩니다. obj가 밖에서 부치nil를 받은 후에 분석 함수를 촉발하지 않고 Block이 지나간 후에 촉발 분석을 합니다.

    결론


    단순 사용__weak은 Block의 변수를 초래하여 실행 과정에서 방출되어 코드상의 논리적 오류를 초래할 수 있다.그래서 Block 내부에서 사용하는 것을 추천합니다__strong.물론 Block 내부에서 사용__strong도 Block 내부에서 실행하는 과정에서 대응하는 대상을 방출하지 않을 뿐 해당 대상이 Block에서 실행될 때 방출되지 않을 것을 보장할 수 없다.
    마지막으로 데모를 첨부하면 파트너가 코드를 다운로드하여 테스트를 할 수 있습니다.

    좋은 웹페이지 즐겨찾기