블록(block)은 Objective-C에서 쓸 수 있는 동적 함수 혹은 클로저(Closure)와 비슷한 기능이다. 필요할 때 동적으로 생성될 수 있고 이름 없이도 구현할 수 있는 등 다른 여러 언어들의 클로저 개념과 상당히 유사하다.
블록이 컴파일될 때는 실제로는 함수 포인터 형식으로 변경되는 것으로 유추된다. 실제 코드에 포인터를 의미하는 *
문자가 사용되지 않지만 nil
을 가질 수 있는 등 포인터로 대체되어 컴파일되는 것 같다.
문법
꺽쇠 즉 ^
문자가 블록을 가리키는 핵심적인 오퍼레이터다.
^{
...
}
위가 블록 문법을 알려주는 가장 기본적인 문법이지만 실제로는 아래와 같은 식의 문법을 쓰게 되는 것 같다.
returntype (^name)(parameters) = ^(parameters) { ... }
parameters라 적어 놓은 부분은 매개변수 목록이 C 함수와 비슷한 방식으로 작성되는 부분이다. 예시를 보면 알 수 있지만 선언 시에는 타입만 명시하고 실제로 구현될 때 각 매개변수 이름을 실제로 결정하는 방식으로 많이 쓴다. 지극히 C스러운 부분이다. 물론 선언 시 이름을 바로 명시할 수도 있다.
하지만 위 문법이 모든 것을 알려주지는 않는다. 상황에 따라 이름 위치가 바뀌는 등 곤란한 느낌이 든다. 그리서 좀 더 실전적인 예제 위주로 정리해 본다.
조금 더 실전적인 예
이제부터 나올 예제는 정수와 문자열을 매개변수로 받고 정수형을 리턴하는 블록 함수를 선언하고 구현하는 방법을 여러 상황에서 나열한다.
메서드 매개변수에 블록 정의하기
아마도 가장 흔하게 사용될 패턴으로 특정 클래스의 메서드에서 블록을 매개변수로 받는 경우다. 이 경우 아래와 같은 식으로 블록 이름은 생략하고 ^
를 끼워 넣어야 한다.
- (void)someMethodWithBlock:(int (^)(int, NSString *))blockFunc {
...
}
이런 식으로 구현한 블록은 아래와 같이 호출할 수 있다.
[someInstance someMethodWithBlock:^int(int value, NSString *name) {
...
}];
반환 값이 없는 블록의 경우 매개변수에서 구현할 때 ^
뒤에 반환 타입을 그냥 생략해도 된다.
클래스 프로퍼티를 블록으로 선언해 보기
프로퍼티의 경우는 일회성이 아닌 지속적으로 호출될 필요가 있는 블록을 담기에 유리하다.
@property (nonatomic, nullable) int (^propertyFunc)(int, NSString *);
위처럼 프로퍼티의 경우라면 ^
뒤에 프로퍼티 이름이 온다. 이 프로퍼티에 블록을 구현해서 지정하는 방법도 일반적이다.
someInstance.propertyFunc = ^int(int value, NSString *name) {
...
}
물론 반환 타입을 안 쓰는 경우라면 생략할 수 있다.
블록으로 지역 함수를 만들어보기
위 문법 항목의 두 번째 문법으로 적어놓은 임시 코드가 해당될 것 같다. 제목대로 지역 변수에 블록을 담으면 로컬 함수처럼 사용할 수 있다.
int (^localFunc)(int, NSString *) = ^int(int value, NSString *name) {
...
};
이렇게 하면 localFunc
라는 변수를 함수처럼 사용할 수 있게 된다.
int res = localFunc(0, @"foo");
같은 코드의 블록을 여러 번 넘기려면 이런 식으로 구현하면 효율적일 것 같다.
블록을 타입과 비슷하게 선언하기
블록을 사용함에 있어 가장 많이 사용되는 스타일이 바로 typedef
등을 이용해 타입을 미리 특정 별명에 선언해 주는 방식이다.
typedef int (^SomeBlockFuncType)(int, NSString *);
위처럼 선언해 두면 이제 기존의 복잡한 블록 문법 대신 SomeBlockFuncType
이라는 이름을 선언 타입으로 쓸 수 있다.
- (void)someMethodWithBlock:(SomeBlockFuncType)blockFunc {
...
}
물론 특정 변수에 담는 경우도 비슷하게 쓸 수 있다.
SomeBlockFuncType localFunc = ^int(int value, NSString *name) {
...
};
사족
사실 블록 관련 글은 다른 블로그에서도 이미 쓴 적이 있고 개인 메모장에도 기록이 되어 있음에도 또 이런 식으로 메모를 남기게 된다. 단순하다. 문법을 자꾸 까먹는다. 그리고 적어 놓은 곳도 까먹는다. 그러니 자꾸만 다시 찾아보고 메모를 하게 된다. 특히 이 글의 사용 예시는 내가 필요한 목적으로 쓰는 부분이다.
그만큼 Objective-C의 블록 문법이 가독성 측면에선 그다지 좋지 않다는 의미일지도 모른다. 애초에 C를 기반으로 하는 언어이기 때문에 어쩔 수 없는 측면이 있기에 이해는 해야겠지만 말이다.
'기술적인 이야기 > 애플 플랫폼 개발' 카테고리의 다른 글
Xcode 프로젝트 Info.plist 실종 사건 (1) | 2023.08.16 |
---|---|
Objective-C에서 인터페이스 공개시키기 (0) | 2023.03.13 |
WKWebView에서 Page Down 구현하기 (268) | 2022.05.08 |
Xcode Playground에서 Swift Package 이용하기 (277) | 2022.04.17 |
Swift에 어울리는 Objective-C 코드 작성하기 (245) | 2022.03.06 |
댓글