[swift] Swift 기초 - 4

Swift 2014. 10. 29. 13:32



4번의 Swift 스터디 자료중 마지막 자료입니다. 





지난 시간에 학습한 내용을 간단히 정리해볼까요?

구조체는 member-wise 생성자를 디폴트로 가지며, pass by value 즉 복사되어 함수에 전달됩니다. 

클래스는 designated / convenience 생상자를 갖으며, pass by reference 즉 참조로 함수에 전달됩니다.

구조체,클래스의 속성으로는 저장속성, 계산속성이 있으며, 속성 옵저버에 대해 간략히 배웠습니다.

서브스크립트를 구현하면 클래스의 데이터를 인데스 문법을 사용하여 접근할 수 있습니다. 

데이터 초기화 역할을 하는 생성자, 그리고 소멸자는 사용한 자원을 해제하는 역할을 담당합니다. 




이번 시간에는...

사용한 객체의 참조 횟수를 추적해서, 필요없을 때 자동으로 해제해주는 ARC, 

상속에 의존하지 않고 클래스를 확장할 수 있는 Extension,

Java 언어에서 인터페이스 역할을 하는 Protocol, 

타입을 인자로 하여 범용타입의 자료구조를 정의할 수 있게 해주는 Generic에 대해 알아보겠습니다.






iOS5.0 부터 Objective-C에서 메모리 관리를 획기적으로 쉽게 만든 ARC는 Swift에서 기본으로 지원합니다.

Automatic Reference Counting 이라는 이름 그대로, 객체마다 참조되는 횟수를 추적하여 

참조횟수가 0이 될때, 자동으로 메모리에서 해제시켜주는 기법입니다. 

ARC의 동작과정을 알아보기 위해,  생성,해제 시점에 출력하는 Person 클래스를 정의하였습니다.




위 할당문 사이사이에 코드 출력문을 삽입하고, 어떤 결과가 나오는지 지켜볼까요?




Person 객체를 참조하는 변수 ref1, ref2, ref3 모두 nil이 되는 순간, 

즉 레퍼런스 카운트가 0이 되는 순간 자동으로 객체가 해제되는 것을 볼 수 있습니다.





사람(Person)이 입주할 수 있는 아파트(Apartment) 클래스를 정의하였습니다. 




위 코드를 실행하면 다음 결과를 출력합니다.



Person 객체의 초기화는 이루어졌지만, 해제가 되지 않았습니다. 무엇 때문일까요? 

네. Apartment 객체의 tenant 속성이 Person을 참조하고 있고,

Person의 home 속성이 Apartment을 참조하고 있기 때문입니다.

이렇게 서로 참조하는 상황을 순환참조(reference cycle)라고 합니다. 

순환참조가 이루어지면 메모리 해제되지 않고 남아있는  메모리 누수가 발생합니다.

Swift에서는 순환참조를 방지하기 위해 2가지 키워드를 제공합니다. 




weak 키워드를 사용하면, 참조횟수를  1증가시키지 않고, 약한참조로 동작합니다. 

참조하는 객체가 메모리에서 해제되면 weak 참조변수는 자동으로 nil로 초기화되어 안정성을 보장합니다.

이런 특성 때문에 optional 타입변수만 weak 참조변수가 될수 있습니다. 



weak 참조는 참조 카운트를 증가시키지 않기 때문에, 

renters["Elsvette"] = nil 실행과 동시에 Person 객체가 해제되고, 

apts[507] = nil 의 의해 Apartment 객체가 해제됩니다.





순환참조를 방지하는 또다른 키워드는  unowned Reference 입니다. 

신용카드(CreditCard)를 소유하는 고객(Customer) 클래스를 정의하였습니다.





신용카드(CreditCard) 클래스는  카드를 소유하는 고객(Customer)을 unowned 로 참조합니다. 

unowned 참조는 말그대로 소유권을 갖지않는 참조로 역시 참조 카운트를 증가시키지 않습니다. 

unowned 참조변수는 nil로 초기화되지 않으며, optional 타입에 사용할 수 없습니다. 

unowned 참조는 보통 생명주기가 타 클래스에 의존적인 클래스에 주로 사용됩니다.

신용카드는 소유주인 고객이 존재하는 동안만 의미를 갖는다는 것을 생각해보세요.




코드 실행결과를 볼까요?



고객(Customer) 객체가 해제되고 신용카드 객체도 해제되어 순환참조 문제가 발생하지 않습니다.


정리하면, 모델링 하는 대상 클래스들의 의존성 여부와 optional  가능유무에 따라 

weak와 unowned 를 구분하여 사용하면 되겠습니다! 





자바에서는 인터페이스, Objective-C, Swift에서는 프토토콜 이라고 합니다. 

프로토콜의 메소드는 디폴트로 required로 동작합니다. 

Thing를 상속하는 Boards 클래스는 Pullable 프로토콜 메소드 pull()을 

구현하지 않았기 때문에 컴파일 에러가 발생합니다. 





이렇게 pull() 메소드를 구현하면 컴파일 에러가 발생하지 않습니다.




인스턴스가 프로토콜을 따르는지 유무를 알기 위해, is, as?, as! 연산자를 사용할 수 있습니다.

is는 특정 프로토콜을 따르는 경우 true,  그렇지 않으면 false를 반환합니다.

as?는 특정 프로토콜을 따르면 해당 타입으로 변환해주고, 그렇지 않으면 nil을 반환합니다.

as!는 특정 프로토콜로 강제 형변환을 시도하며, 실패할 경우 런타임 에러가 발생합니다. 






Extension은 Objective-C에서 카테고리와 유사합니다.  

기존에 존재하는 클래스를 변경하지 않고, (기능을) 확장할 수 있습니다.

코드의 재사용성을 획기적으로 높일 수 있는 Swift 언어의 장점 중 하나입니다.

Double 클래스를 확장하는 Extension을  만들고, 거리단위를 환산하는 메소드를 정의했습니다.





Extension 에 정의한 메소드를 활용하면, 짧고 명료한 방법으로

다양한 단위의 Double 형 부동소수값을  미터 단위로 변환할 수 있습니다.





역시 정수형 횟수만큼 특정 task 함수를 반복하는 코드를 쉽게 정의할수 있습니다.





정수형에 제곱을 구하는 Extension 메소드입니다.






Extension은 서브스크립트와도 조합하여 사용할 수 있습니다. 

index에 해당하는 십진수의 자리 수를 구하는  subscript를 정의하였습니다.





문자의 자음, 모음 유무를 출력하는 Extension 메소드를 정의하였습니다.





다음과 같은 결과를 출력합니다.






제네릭은 컬렉션, 구조체, 클래스에 타입을 매개변수화하여 전달할 수 있는 기능입니다. 

만일 제네릭이 없다면, 스택 데이터 구조를 정의할 때, 정수형, 문자형, 부동소수형 등 모든 타입에 대해

스택 데이터 구조를 각각 정의해야 할 것입니다.

제네릭은 타입에 대한 유연성과 안정성을 제공해주는 유용한 기능입니다.





앞서 정의한 정수형 스택에서, 타입T를 매개변수화하여 제네릭으로 정의하였습니다.





동일한 코드로, 정수형, 문자열 등 다양한 타입의 스택을 사용할 수 있습니다.



4번의 스터디를 통해 간략하게 나마 Swift 언어에 대해 훑어보았습니다.  

Swift 언어는 지금도 시시각각으로 변화하고 있으며 발전하고 있습니다. 

혹자는 어차피 바뀔건데 왜 벌써 공부해 ?라고 할수도 있지만, 무엇이든지 변화되는 과정을

지켜보는 것은 즐겁습니다. 그 변화 과정속에서 혹시 남들이 보지못하는 혜안을 가지게 될지 모르잖아요?






'Swift' 카테고리의 다른 글

[swift2] New in Swift2.0  (0) 2015.06.19
[swift] Apple Swift Blog  (0) 2015.06.10
[swift] Swift 기초 - 4  (0) 2014.10.29
[swift] Swift 기초 - 3  (1) 2014.10.29
[swift] Swift 기초 - 2  (0) 2014.10.29
[swift] Swift 기초 - 1  (1) 2014.10.29