Swift는 점점 더 많은 iOS와 OS X 개발자들이 선택하는 언어가 되고 있습니다. Swift는 빠르고, 단순하고, 깔끔하며 Objective-C 개발자들에게는 제공되지 않는 많은 기능들을 가지고 있습니다.
반드시 요구되는 사항은 아니지만, 여러 프로젝트들이 Swift의 속도, 강력함 그리고 안정성의 이점을 얻기 위해 Objective-C에서 Swift로 전환되고 있습니다.
프로젝트 중 하나는 실제 소프트웨어 프로젝트는 아닙니다. - 이는 iOS Games Programming Cookbook의 Swift 판 입니다. Swift 버전으로 책을 업데이트 하는 작업을 시작했을 때, 우리가 첫 번째로 해야 했던 것은 바로 책의 모든 코드를 새로운 언어로 재 작성하는 것이였습니다. 그렇지만, 바로 한 언어에서 다른 언어로 옮기는 작업은 쉽지 않습니다.
Swift는 Objective-C에 비해 여러 중요한 방면에서 다르게 동작하며, 그것은 여러분이 작성한 Swift 코드가 Swift에서 어떻게 동작하는지 알아야 한다는 것을 의미합니다.
암시적으로 추출되는 Optional은 피하라
Optional은 Swift에서 가장 흥미로운 기능 중 하나입니다. 이는 null 문제를 매우 영리한 방법으로 다루고 있습니다.: Optional이라 불리는 특별한 클래스를 제외한 모든 객체는 절대 nil을 허용하지 않습니다.
예를 들어, 문자열 변수는 항상 일정 문자열을 포함해야만 하며, 절대 nil이 허용되지 않습니다. - 이는 문자열을 지니지 않는 것을 허용하지 않습니다.
반면에 Optional 문자열은 nil이 허용됩니다. 여러분이 어떤 것이 Optional 인지 아닌지를 판단하는데 도움을 주기 위해, Swift는 Optional을 다룰 때 특별한 문법을 사용하도록 요구합니다.
Optional 문자열을 선언할 때, 여러분은 ? 를 사용합니다:
var optionalString : String?
위 Optional 문자열을 사용하고 싶을 때마다, 여러분은 첫 번째로 Optional이 값을 지니는가를 확인해야만 합니다.
optionalString?.length // will only run if optionalString is not nil
여러분이 이 Optional 문자열을 사용하길 원할 때마다, 여러분은 반드시 첫 번째로 Optional이 값을 지니고 있는지 다시 한번 보기 위해 ? 를 사용하여 확인해야 합니다. 만일 변수가 값을 지니고 있지 않다면 계산식은 정지하게 됩니다.
참고로, 만약 변수가 값을 가지고 있지 않다면, 여러분의 실행한 속성이나 메소드의 결과값 역시 Optional이 됩니다. 예를 들면:
var myString = "Hello"
var myStringLength = myString.utf16Count // = non-optional Int
var myOptionalString : String? = "Hello"
var myOptionalStringLength = myOptionalString?.utf16Count //optional Int
만약 여러분이 어떻게 동작하는지 이해하지 못한다면 ? 를 사용하는 모든 것들은 혼란스러운 에러 메시지를 야기할 수 있습니다. 마지막 줄을 글자 하나만 변경해서 다시 한번 살펴봅시다:
var myOptionalStringLength = myOptionalString.utf16Count
여러분이 위 코드를 따라한다면 Xcode는 아래와 같은 에러를 발생 할 것 입니다:
'String?' does not have a member named 'utf16Count'
언듯 보기에, 이 에러 메시지는 이해가 되지 않는데, 이는 우리는 문자열 객체가 utf16Count라 불리는 속성을 지니고 있다는 사실을 확실히 알고 있기 때문입니다.
그러나, 여러분이 Optional은 문자열 객체와 완전히 다른 타입이다 라는 것을 인지하게 된다면 좀 더 이해하기 쉬울 것 입니다.
Optional 문자열 변수는 문자를 (때때로) 저장하고 있지만, 그 값 이외에는 그 무엇도 가지고 있지 않습니다. 실제로, Swift 라이브러리에 Optional은 아래와 같이 정의되어 있습니다:
enum Optional<T> : Reflectable, NilLiteralConvertible {
case None
case Some(T)
/// Construct a `nil` instance.
init()
/// Construct a non- `nil` instance that stores `some`.
init(_ some: T)
/// If `self == nil`, returns `nil`. Otherwise, returns
`f(self!)`.
func map<U>(f: (T) -> U) -> U?
/// Returns a mirror that reflects `self`.
func getMirror() -> MirrorType
/// Create an instance initialized with `nil`.
init(nilLiteral: ())
}
보시다시피, Optional은 그 차체로 완전한 타입입니다. 이는 단지 어떠한 값을 가지고 있는 것입니다.(첫째 줄에 정의된, 제네릭 타입 T 로 대변되는 값). 그렇기 때문에, Optional이 "myOptionalString"은 "utf16Count" 속성이 없다라고 하면 컴파일러는 이를 전적으로 신뢰하게 됩니다. 여러분은 ? 를 사용하여 Optional의 값을 추출 해야만 합니다.
그러나, 너무 많은 ? 가 여러분의 코드를 차지하는 상황이 발생 할 수 있습니다.
또한, 추출한 Optional의 값 그 자체가 Optional이라는 점도 성가실 수 있습니다.
대신, 여러분은 Optional이 암시적으로 추출되도록 선언 할 수도 있습니다. 이것은 여러분이 nil이 허용되는 변수를 가지게 된다는 것을 의미하지만, 변수의 값에 접근하려고 시도 했을 때, 여러분은 ? 를 사용하여 값을 추출할 필요가 없습니다. - 여러분은 값을 요청하고, 얻게 됩니다.
이것은 덜 지저분한 코드를 의미 합니다!
var myImplicitString : String! = "Hello"
myImplicitString.utf16Count // works!
myImplicitString = nil // also works!
암시적으로 추출된 Optional의 문제점은 안정성이 보장되지 않는다는 것입니다. 만일 여러분이 암시적으로 추출된 Optional의 값에 접근하려고 한다면, 그리고 그것이 nil이라면, 여러분의 프로그램에서는 크래시가 발생합니다. 이는 실제로 의도적인 것입니다: Optional의 요점은 값이 nil이 될 수 있을 때와 항상 유효한 값을 가질 수 있을 때 에 대해 여러분이 판단하도록 하는 것 입니다. 암시적으로 추출된 Optional은 이러한 안정성에 위배됩니다.
만일 여러분의 코드를 더 안전하게 작성하고 싶다면, 암시적으로 추출되는 Optional은 사용하지 마십시오. 그대신, if let 문법을 사용하세요:
if let theString = myOptionalString {
// do work with theString, which is guaranteed to be non-nil
// you also don't need to use ? to access the value
}
if let 문법은 여러분에게 옵셔널 바인딩을 수행하도록 합니다. - Optional 값을 검사하고, 이를 nil이 되지 않는 것을 보장하는 상수값에 저장합니다. 여러분은 여러분이 사용하는 진짜, 유효한 값임을 확신하는 상수값과 함께 모든 작업을 수행 할 수 있습니다.
if let은 또한 여러분이 타입케스트를 안전하게 수행하도록 합니다. 예를 들어, 타입이 AnyObject - 문자 그대로 모든 종류의 객체를 의미합니다. - 인 객체를 하나 생성했다고 합시다:
var someObject : AnyObject = ...
또한 여러분은 이 객체가 NSURL 임을 확신하고, 이 객체로 어떤 작업을 하길 원한다고 가정해 봅시다.
let someURL = someObject as NSURL
만일 someObject가 실제로 NSURL 로 전환 가능하지 않다면, 여러분의 프로그램은 크래시를 발생할 것입니다. 대신에, 여러분은 변환 가능한지를 확인하기 위해 if let 구문을 as? 연산자와 함께 사용해야 하며, 변환이 가능하다면, 보시는 바와 같이 결과값을 상수에 바인딩합니다:
if let someURL = someObject as? NSURL {
// code here will only run if the typecast is successful
// in here, 'someURL' is guaranteed to be a valid NSURL object
}
보신 바와 같이, Swift에서는 값과 타입의 모호성을 처리하는데 있어 안전하지 않은 검사를 하는 방법 보다 더 나은 것들이 있으며, 안전하게 검사하기 위해 Swift의 내장 지원을 사용하는 것이 훨씬 더 나은 방법입니다.
이전 글 : 새로운 PHP
최신 콘텐츠