12월, 2019의 게시물 표시

thread와 dispatch queue와의 관계

이미지
thread와 dispatch queue와의 관계 test case를 작성하던 중 수행하는 코드가 main thread에서 동작하는지 확인해야하는 상황이 있었습니다. 그 상황을 만들기 위해서 global queue에서 main queue를 동작시켜 해당 코드가 main thread인지를 확인하는 코드를 작성했습니다. 그런데 그 test case는 통과하지 못하고 계속 실패했습니다. global queue가 동작한 thread는 background thread였는데 그 곳에서 dispatch_sync로 main queue를 동작시키면 main thread가 아닌 background thread에서 main queue를 동작시켜서 문제가 발생했습니다. main queue는 무조건 main thread에서 동작한다고 알고 있어서 dispatch로 하면 당연히 main thread라고 생각했습니다. 그런데 sync로 동작할 때는 제 예상하고 달랐습니다. test case에서 async로 동작을 시켰더니 test case를 통과했습니다. sync와 async 사이에 차이가 단순히 동기화만의 문제가 아닌 다른 차이가 있다는 생각이 들던찰라에 xcode 업데이트 후에 다시 위의 상황에서 dispatch_sync로 main_queue를 실행했더니 이번에는 main thread에서 동작했습니다. Xcode버그이거나 simulator가 오작동을 일으켰던 것 같습니다. 이번일을 겪고 나서 dispatch_queue와 thread의 관계에 대해서 알아보고 싶어서 이 글을 쓰게 되었습니다. 먼저, thread에 대해서 알아보겠습니다. thread는 어플리케이션에서 다른 실행경로를 만드는 역할을 합니다. 프로세스에 할당된 메모리를 공유하며 여러개의 thread가 동시에 실행될 수 도 있습니다. 프로세스와 다른 점은 프로세스 끼리는 메모리를 공유하지 않지만 같은 프로세스 안에 있는 thread끼리는 메모리를 공유합니다. 한 프로세스는 여

unowned vs unowned(safe) vs unowned(unsafe)

unowned vs unowned(safe) vs unowned(unsafe) unowned를 사용하는 방법은 아래처럼 총 세가지가 있습니다. unowned unowned(safe) unowned(unsafe) 대부분 unowned만 사용하며 나머지는 크게 사용할 일이 없습니다. 그렇다면 나머지 2개는 왜 존재할가요? 우선은 각각에 대해 먼저 알아보겠습니다. unowned(safe) unowned(safe)는 참조를 사용할 때 런타임 safety checker가 먼저 검사를 수행합니다. 런타임 safety checker는 사용하는 메모리가 실제 사용하는 객체가 맞는지를 확인합니다. 참조한 객체가 해제가 되어 더이상 메모리가 유효한 객체가 아니라면 런타임 safety checker에 의해 즉시 런타임 오류가 발생합니다. unowned(unsafe) unowned(safe)는 참조를 사용할 때 런타임 safety checker가 비활성화됩니다. 참조한 객체가 해제된 후에 사용하면 대부분 런타임 오류가 발생하지만 발생하지 않고 정상동작이나 엉뚱한 동작을 할 수 있습니다. 런타임 safety checker에 의해 메모리를 조사하지 않기 때문에 해당 주소가 동일한 클래스의 객체로 변경되면 그 객체에서 정상동작을 할 수 있으며 다른 객체로 메모리가 교체되었다면 예상하지 못한 엉뚱한 동작을 할 수도 있습니다. 그래서 안전하지 않다고 표현하는 것입니다. unowned(unsafe)를 사용하려면 사용하는 사람이 안전하게 동작하도록 모든 책임을 가져야합니다. unowned unowned는 대부분의 경우 unowned(safe)와 동일하게 동작을 합니다. 다만, 컴파일할 때 옵션에 -Ofast를 설정하면 unowned(unsafe)로 동작합니다. Int가 32 bit에서는 4byte로 동작하고 64bit에서는 8byte로 동작하는 개념과 비슷하다고 할 수 있습니다. 각각에 대해서 알아보았습니다. 이제 un

weak와 unowned의 차이는?

weak와 unowned의 차이는? 메모리 참조에 weak와 unowned 참조가 있습니다. weak와 unowned는 모두 class타입에서만 사용할 수 있으며 메모리의 소유를 주장하지 않습니다. weak 참조 먼저, weak에 대해서 알아보겠습니다. weak 참조는 메모리의 retain count를 증가시키지 않고 객체를 저장합니다. retain count를 증가시키지 않기 때문에 순환참조 문제를 방지할 수 있습니다. 참조한 메모리가 해제되었을 때는 ARC에 의해 자동적으로 nil로 초기화됩니다. 따라서, dangling pointer가 되는 것을 걱정하지 않아도 됩니다. 사용법은 변수 키워드 앞에 weak를 붙이면 됩니다. weak는 nil로 초기화될 수 있기 때문에 Optional type만 가능합니다. 당연히 let이 아닌 var로 선언해야합니다. weak var reference : Optional type weak 참조는 어디에서 사용할 수 있을 가요? 바로 순환 참조가 발생할 수 있는 참조나 delegate, closure에서 사용할 수 있습니다. class Account { var bank : Bank ? deinit { print ( "deinit Accout" ) } } class Bank { var account : Account ? deinit { print ( "deinit Bank" ) } } var account : Account ? = Account ( ) // account retainCount: 1 var bank : Bank ? = Bank ( ) // bank retainCount: 1 account ? . bank = bank

closure에서는 왜 self를 사용해야 할까?

이미지
closure에서는 왜 self를 사용해야 할까? class에서 closure를 사용할 때 closure 안에서 객체의 변수 또는 함수에 접근할 때 self를 붙여서 사용을 해야합니다. class안에서는 self없이 변수 및 함수를 사용할 수 있고 로컬변수도 바로 사용할 수 있는데 왜 closure에서는 self를 붙여야 할가 궁금했습니다. objective-c에서도블럭안에서 self를 명시적으로 사용해야합니다. 물론, self없이 사용은 가능하지만 warning 메시지가 발생합니다. 이 부분을 이해하기 위해서는 먼저 capture list에 대해서 알아야합니다. capure list는 closure 안에서 사용할 객체를 정의하는 목록입니다. 문법 구조는 아래 와 같습니다. let closure: (Bool)->(T) = { [capture list 작성 ] (parameter) in // closure body } capture list는 여러개 정의가 가능하고 콤마(,)로 구분합니다. 정의한 항목이 class인 경우 ‘weak’ 또는 'unowned’를 함께 사용할 수 있습니다. 예를 들면, 아래 코드처럼 작성할 수 있습니다. func testCaptureList ( ) { let aString1 : String = "capture1" let aString2 : String = "capture2" let closure : ( Bool ) - > ( ) = { [ capture1 = aString1 , capture2 = aString2 ] ( success : Bool ) in print ( capture1 , capture2 ) } } aString1은 capture1에 할당하고 aString2은 capture2에 할당했습니다.

swift init 상속에 대해서 알아봅시다.

이미지
swift init 상속에 대해서 알아봅시다. swift를 처음 접했을 때 init의 상속관련해서 어떤 경우에는 상속이 이루어지고 어떤 경우에는 상속이 되지않아서 이해하기 어려운 부분이 있었습니다. 이번 기회에 init의 상속 관련 내용을 정리하려고 합니다. 먼저, 지정 초기화(designated initializer)와 편의 초기화(convenience initializer)의 관계를 정리하면 3가지 법칙이 있습니다. 지정 초기화는 부모의 지정 초기화를 호출해야합니다. 편의 초기화는 부모가 아닌 자신의 초기화를 호출해야합니다. 편의 초기화는 마지막 지점에서는 지정 초기화를 호출해야합니다. 간단히 다시 정리하면 지정 초기화는 부모의 지정 초기화에게만 위임을 할 수 있으며, 편의 초기화는 자신의 편의 초기화 또는 지정 초기화에게만 위임할 수 있습니다. 아래 이미지로 설명하면 지정 초기화는 위 방향으로만 위임하고 있으며, 편의 초기화는 옆 방향으로 위임하고 있습니다. 아래 이미지는 좀더 복잡한 경우이며 아래의 경우도 위에 설명드린 3가지룰을 지키고 있습니다. 다음으로 알아볼 사항은 property 초기화입니다. swift는 두 단계 초기화로 이루어져 있습니다. 첫번째 단계에서는 property를 초기화를 수행합니다. 먼저 자신의 property를 모두 초기화하고 그 다음 부모의 property를 초기화합니다. 모든 property를 초기화하고 나면 두번째 단계를 진행합니다. 두번째는 저장된 property를 조작할 기회를 부여합니다. 이때는 자신이 아닌 부모부터 기회를 부여받습니다. objective-c와 비교하면 swift 초기화 방식이 다르다고 생각할 수 있습니다. objective-c의 초기화 함수를 보면 부모부터 진행하고 자기 자신의 초기화 코드가 가장 나중에 진행되기 때문입니다. 사실 objective-c의 초기화 단계도 swift의 초기화처럼 두단계로 구성되어 있습니다. 다만, obj