2016년 7월 21일 목요일

[Objective-C] Block Syntax 초간단정리

하도 잊어먹어서 - 거기다 요즘은 Swift만 써대다보니 더욱 더 잊어먹어서 - Objective-C 블럭 문법(Block Syntax)을 자주 쓰는 것들 위주로 예제와 함께 정리해본다.

typedef 로 타입으로 만들기

typedef RETURN_TYPE (^NAME)(PARAMETERS...);
정의 예제(Definition Example):
typedef void (^SomeHandler)(NSError *error);
구현 예제(Implementation Example):
- (void)someWorkWithCompletion:(SomeHandler)handler {
  ...
}
이름이 리턴 타입 뒤에, 즉 중간에 끼어 있기 때문에 많이 헷갈린다. -_-;

바로 Parameter Field 로 정의하기

fieldName:(RETURN_TYPE (^)(PARAMETERS...))parameterName
정의 예제(Definition Example):
- (void)someMethodWithCompletion:(void (^)(NSData *data))completionHandler;
구현 예제(Implementation Example):
[someClass someMethodwithCompletion:^(NSData *data) {
  ...
}];

Property로 정의하기

RETURN_TYPE (^)(PARAMETERS...)
정의 예제(Definition Example):
@property (nonatomic, strong) void (^completionHandler)(NSData *data);
구현 예제(Implementation Example):
someClass.completionHandler = ^(NSData *data) {
  ...
};
프로퍼티로 정의하는 경우에도 이름이 가운데에 끼어서 좀 불안한(?) 모양세다.

변수로 생성하기

RETURN_TYPE (^BLOCK_NAME)(PARAMETER_TYPES...) = ^RETURN_TYPE(PARAMETERS...) { ... };
구현 예제(Implementation Example):
void (^someBlock)(NSData *) = ^void(NSData *data) {
  ...
};

[obj methodUsingBlock:someBlock];
[obj anotherMethodUsingBlock:someBlock];
만약 블럭을 여러 곳에서 공통적으로 쓴다면 변수 등으로 정의해서 참조 할 수 있다.

보너스: 블럭 외부의 변수를 블럭 내부에서 세팅하기

Swift 클로져의 경우는 별 상관 없는데 Objective-C 블럭의 경우 외부 변수에 뭔가를 쓰는 것은 기본적으로 금지되어 있다. (즉 읽기만 가능하다.) 이를 쓰기 가능하게 풀려면 '__block' 을 쓰려는 변수 선언 앞에 달아주면 된다. 아래 코드는 GCD Dispatch 에서 사용하는 예이다.
__block int result = 0;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  ....
  result = [some workAndResult];
});

잡설

리턴타입이나 인자가 없는 경우 void를 사용하면 된다는 거야 다들 알 거라 생각되어서 생략했다. C를 잘 모른다면 Objective-C를 반 밖에 모른다는 의미이니 어느 정도는 파악해 두자.

블럭의 경우 스위프트의 클로져와 비교 할 수 밖에 없는 기능인데, 유감스럽게도 Objective-C의 블럭 문법은 클로져에 비해 좀 복잡하고 읽기 어렵다고 생각된다. 그래서 함수형 프로그래밍에서도 잘 언급 안되는 것 같고 그래서 내 경우 로컬 변수에 블럭을 할당하는 방법은 거의 쓰지 않는다. 반면에 스위프트에선 좀 복잡해 진다 싶으면 바로 클로져로 분리해 버리기도 하는 등 자주 쓰이는데 말이다.

물론 쓸 게 없어서 쓰는 잡설일 뿐이다. ;-)

댓글 없음 :