iOS5부터인가 나왔던 기능으로 알고 있는데 block코딩과 더불어 생소한 문법 중 한놈이다.

굳이 써야되는 필요성을 느끼지 못한놈인지라 넘겨두고 있었는데 최근 비동기처리가 필요한 플젝을 하면서

어쩔수 없이 조금 공부하게 되었다.

정말 간단하게 구현되고 편리하므로 아마도 자주 써줘야겠다.

어쨌든 내가 아는한도내에서 두가지 정도 메모해 둔다.


첫번째 제일 자주 쓰는 구문. 이건 싱글톤 처리할때 쓰는 패턴이다. 다른방법도 있지만(인스턴스가 nil인지 아닌지 비교해서 분기해주는...)

어쩐지 이게 더 멋있어 보인다. 

쓰는 방법은 dispatch_once_t 라는 변수를 선언해주고 dispatch_once라는 메소드에 초기화 처리를 해주면 메소드 이름처럼 

딱 한번만 실행한다. 그러니 결과적으로 싱글톤이 됨.


+ (AVAudioPlayerManager*)sharedAVAudioPlayerManager {

    static dispatch_once_t pred = 0;

    __strong static id _vrObject = nil;

    dispatch_once(&pred, ^{

        _vrObject = [[self alloc] init];

    });

    return _vrObject;

}


두번째로 비동기를 위해 스레드 처리할 경우. 예를들어 메인스레드에서 시간이 걸리는 처리를 해버리면 

당연히 화면이 멈추는 현상이 나타난다. 왜냐면 화면처리는 메인스레드에서 처리되므로.. 

바꾸어 말하면 시간 걸리는건 메인스레드에서 처리하지 않는것이다. 다만 화면상태를 바꾸고 싶을땐 메인스레드에서 처리

해야 하므로 그 부분만 메인스레드로 넘기는 것이 포인트.


1.일반큐와 메인큐를 각각 선언한다. 

2.스레드를 사용하기 위해 dispatch_async 라는 메소드를 선언하고 일반큐를 파라메터로 넣는다.

3. 다음 처리로직안에 화면제어를 할 필요가 있는 처리에 대해선 메인큐(메인스레드)로 넘겨준다.


정말 간단하다. 백문이불여일견! 직접 소스를 보자.


dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    dispatch_async(globalQueue, ^{

    

        //시간이 걸리는 처리를 한다고 치자.

        int count = 0, i;

        for(i = 0; i < 10000; i++){

            NSLog(@"count = %d", count);

            count++;

        }

        

        //진행상태를 화면에 표시해주기 위해 메인스레드에 화면변경로직을 코딩.

        dispatch_async(mainQueue, ^{

            [self updateProcress:[self logStringWithCount:count]];

        });

        

        //또 시간이 걸리는 처리가 있다고 한다면...

        for(i = 0; i < 10000; i++){

            NSLog(@"count = %d", count);

            count++;

        }


        //끝났을 경우의 처리를 해준다. 여기서도 메인스레드로 처리해줌.

        dispatch_async(mainQueue, ^{

            [self updateProcress:[self logStringWithCount:count]];

            [_indicatorView stopAnimating];

            _startButton.hidden = NO;

        });

    });


Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

인류문명의 발달은 잉여노동력 그리고 적절한 환경에 의한 결과라는 제레미다이아몬드라는 유명한 아저씨의 주장이 요 며칠간 가깝게 다가왔다.

지금 마치 내상황이 잉여노동력(할일없음) + 적절한 환경(프로젝트 끝나감) 이므로 저아저씨 말대로라면 뭔라도 해야 될 상황이다.


프로젝트는 슬슬 끝나가고 할일은 없고.. 인터넷 서핑도 하루이틀이지.. 

잉여력이 넘치고 넘치던 찰나 결국 남는 잉여력을 소스코드를 이쁘게 고치는데 사용키로 했다.


지금까지 딜리게이트을 남발하면서 막개발을 해 왔는데 이번기회에 iOS5부터인가 지원되지 시작한 blocks비동기처리 방식를 써볼까? 라는 생각이 든것이다.


이제까지 문법자체가 생소해서 쓰고 싶지 않았는데 시계바늘을 본드에 붙여놓은듯 시간이 가질 않으니 어쩔수 없다.

결과적으론 익숙해지는데 조금 시간이 걸렸으나 한번 적용해보니 코드량이 상당히 줄어드는걸 체감했다.

더이상 딜리게이트를 남발하지 않으리...


그럼 일단 block방식으로 코딩하기 위한 문법부터 살펴보자.


블럭구문 기본적인 선언방법

^(파라메터,...) {

    //실행로직

};

 

블럭구문을 대입할 경우의 코딩

반환값 (^변수명)(파라메터,...) = ^(임시 파라메터...) {

    //실행로직

};


여기까지만 보면 어떻게 하라는 얘기인지 모를것이다. 직접 짜보자.


블럭구문으로 test라는 함수작성

int (^test)(int) = ^(int x) {

    return x + x;

};

 

// 결과출력

NSLog(@"%d", test(10));



블럭구문을 typedef로 정의할땐 이렇게 한다. 일반적으로 사용하는 패턴이므로 숙지해 두자.

typedef 반환값 (^변수명)(파라메터,...) 


블럭구문내에 변수사용하기.

__block를 변수앞에 붙이면 블럭구문내에서 값변경이 가능하다.

물론 붙이지 않아도 참조는 가능.


__block int x = 300;

void (^print)(void) = ^(void) {

    x++;

    NSLog(@"%d", x);

};


자.. 여기까지는 기본적인 사항이고 실제로 하고싶은 블럭구문을 메소드에 넘겨주는 걸 해보자.

- (void)example:(double (^)(int, int))func {

int i = 3;

int j = 4;


if(func(i,j) > 5) {

  //처리1...

}else {

  //처리2...

}

}


이런식으로 쓴다. 파라메터로 받은 블럭구분 결과로 처리가 가능하다. 이전엔 이와같은 처리를 딜리게이트로 해결했었다.


실제 호출될 경우에 블록구문내 처리를 하도록 코딩하자.

[self example:^(int n1, int n2) {

//실행처리

    return i+j;

}];


자 여기서 아까 언급했던 typedef 를 상기해보자.

그렇다 메소드에 넘기는 블럭구문을 간단히 정의하여 메소드길이를 줄일수 있다.


//이렇게 정의한 다음..

typedef double (^calcHandler)(int a, int b);



//이렇게 바꾸어 쓸수 있다.

- (void)example:(calcHandler)func {

...

}


딜리게이트의 경우는 프로토콜 정의해주고 그걸 받는쪽에서 위임받아서 처리해주는 구문까지 해야하므로 상당히 코딩량이 많아지는데 반해서 블럭은 상당히 코드를 줄어든다.


조금 설명이 부족한거 같아 한가지 예를 더 들어보자. 

어떤 특정 메소드를 실행이 끝난뒤 후처리를 해주는 메소드를 만들어보자.

블록구문이 사용된 우리가 흔히보는 메소드이다.

[self.navigationController dismissViewControllerAnimated:(BOOL) completion:^{

        //TODO: 

        //화면이 닫힌후 후처리.

    }];

    


먼저 블럭구문부터 관찰해보면 반환값, 파라메터도 없는 블럭이다.

^{ 

//TODO: 

}


위와 같은 처리를 하는 calcTime라는 이름의 메소드를 만들어보자. 그리고 이 메소드가 실행이 완료되면 실행되는 블럭을 만들어 보자.


우선 메소드 선언.

- (void)calcTime:(void ^(void)handler;


그리고 메소드 정의

- (void)calcTime:(void ^(void)handler {


//무쟈게 오래걸리는 처리가 있다고 치자..

//...

//처리가 다 끝난부분에서 블럭구문을 실행하게 한다.

handler();

}

    

    

실제 호출하여 사용할때에는..

[self calcTime:^{

//이메소드 끝날때 처리할 내용 코딩..

}];



써놓고 보니 별 내용없네.. 

테스트하면서 코딩한게 아니라서 소스에 오류가 있을수 있으므로 참고하시길..


Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요