티스토리 뷰
블락의 실체
블락을 선언할 경우 실제로 컴파일러에의해 생성되는 코드에서는 __block_literal 이라는 구조체(struct) 형태로 선언이 된다.
이 구조체 안에는 isa 정보가 포함되어있어서 결국 Objective-C의 객체의 특성을 가지게 된다.
일반적으로 객체들은 힙(heap)에 잡히게 되지만 블락은 특이하게도 스택(stack)에 할당되는 객체이다.
이는 일반적으로 블락이 사용되는 범위가 블락이 선언되어있는 동일 범위에서 벗어나지 않기 때문이다.
즉, 스택에 할당하게 되면 실행 속도 측면에서 힙에 비해 유리하기 때문에
실행속도 최적화를 위해 기본적으로 스택에 할당을 하게된다.
디버거로 할당된 블락 변수를 조사해보면 위 그림과 같이 구조체로 되어있다.
구조체 내부 변수들에서 볼 수 있듯이 해당 구조체는 블락 호출시 실행될 함수포인터를 가지고 있으며,
실행 시 필요한 해당 범위 내 변수들도 저장하여 갖고 있기 때문에 해당 변수들이 저장된 크기만큼 Size 가 잡혀있는 것도 볼 수 있다.
블락의 변수 범위
지역 스택(stack-local) 데이터가 유효한 범위는 블락을 정의하는 부분을 감싸는 바로 위 중괄호 { } 범위이다.
위 코드에서 for문의 중괄호 범위를 벗어날 경우 해당 범위 밖에서의 블락은 유효하지 않다.
블락 내부에서 사용된 변수들이 블락이 선언된 범위의 스택에 복사되어 저장되는데,
이것이 해당 중괄호 범위를 넘어가는 순간 유효하지 않기 때문이다.
블락 스토리지
위에서 살펴본 바와같이 블락을 만들때 실제 블락이 실행될 때를 대비하여
해당 scope에 존재하는 변수들을 저장하게 되는데
이러한 변수들이 저장된 저장소를 블락스토리지(block storage)라고 부른다.
위에서 설명했듯이 블락스토리지는 최적화를 위해 처음에는 스택에 변수들을 저장한다.
하지만 스택에만 저장되어 있는 경우, 해당 scope를 벗어나게 되면 더이상 블락을 사용할 수 없게 되는 문제가 발생한다.
이를 해결하기 위해 명시적으로 Block_copy() 혹은 [blockObject copy] 를 호출하여
블락스토리지를 힙으로 복사하여 이동시켜야만 한다.
이 경우, 동일 블락 내부의 동일한 변수라도 다른 메모리 주소값을 가지게된다.
__block 키워드
변수선언시 __block 키워드는 블락을 만들 때
해당 변수를 어떤식으로 저장해두고 있을지를 정하게 되는 스토리지 타입 변경자(storage type modifier) 이다.
컴파일러는 블락내부에서 사용된 해당 enclosing scope에 해당하는 변수들에 대해,
- 객체일경우 자동으로 retain한다.
- 객체이고 __block 키워드가 있을경우에는 retain하지 않는다.
- 기본타입(primitive type)일 경우에는 const 형태로 value copy되어 전달된다.
- 기본타입(primitive type)이고 __block 키워드가 있을 경우에는 reference형태로 전달된다.
위 그림에서 블락 내부 x는 레퍼런스를 전달받았기 때문에 값을 수정할 수 있다.
블락에 대해 retain 을 하는 것이 의미가 있을까?
블락에서 사용하는 해당 범위내의 변수들은 스택에 저장되어 있기 때문에,
블락에 대해 retain을 하더라도 블락스토리지에 들어있는 범위 내 변수들은 아무런 영향을 받지 않고
scope를 넘어서는 순간 해제된다.
때문에 블락에 대해서는 copy와 release 오퍼레이션만 적용가능하며 retain 오퍼레이션은 큰 의미가 없다.
블락을 프로퍼티로 사용하기
블락을 프로퍼티로 사용할경우에도 copy 키워드는 필수적이다.
@property (copy) (^void)testBlock(void) 형태로 적어주면 된다.
해당 블럭이 블럭 내에서 블럭이 선언될 당시의 스택 프레임에 참조하는 변수들이 없다면
copy를 안해도 되지만 그렇지 않을경우 꼭 필요하다.
ARC환경에서 block을 사용할 경우 이미 컴파일러가 block 객체가 단순히 retain되면 안되고
copy가 되어야 한다는 사실을 알고있기 때문에 block을 대입할 경우 자동으로 카피한다.
하지만 해당 변수가 해당 블락의 signature로 정확히 정의되어 있어야만 이 기능이 동작하며,
단순히 id 타입으로 정의되어있는 경우 제대로 작동되지 않으니 주의해야 한다.
참고 사이트
http://www.letmecompile.com/objective-c-block-%EB%8F%99%EC%9E%91-%EC%8B%AC%EC%B8%B5-%EB%B6%84%EC%84%9D/#fn:1
'iOS 개발 > iOS' 카테고리의 다른 글
- Total
- Today
- Yesterday
- set
- docker
- ios
- applicationWillResignActive
- AWS
- dictionary
- Arc
- thread
- EffectiveObjectiveC
- CGImage
- Swift 3.0
- Swift
- NSManagedObjectContext
- NSManagedObjectModel
- Swfit
- NSManagedObject
- UIView
- Swift3
- HTTP
- 읽기 좋은 코드가 좋은 코드다
- Block
- optional
- Swift 3
- coredata
- 꺼내먹어요
- delegate
- string
- CIImage
- workerThread
- RunLoop
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |