2014년 6월 17일 화요일

Objective-C에서 Swift로 넘어가기

Objective-C 개발자가 스위프트(Swift)로 넘어가기 위해 필요한 지식을 약간 모아봤다.

세미콜론을 안써도 된다

라인의 끝에 세미콜론(;)이 와야하는 C의 주박이 사라졌다.

물론 써도 된다. 한 라인에 여러 라인의 내용을 적어야 할 때라면...

[관련글] Swift - 기본 공통사항

기본 타입이 사라졌다

스위프트에선 int 나 float 나 double 이나 char 같은 C식 기본 타입이 사라졌다.

대신 Int 나 Float 나 Double 이나 Character 같은 구조화된 타입을 맞이하자.

누군가는 포인터 개념도 없다는 것에 환호할지도 모를 것 같다. 물론 레퍼런스 개념은 남아있으니 주의하자.

[관련글] Swift - 변수와 상수 그리고 타입​

변수와 상수 그리고 mutable

변수는 var로, 상수는 let으로 선언하는데 이는 mutable과 immutable 개념과 연관지어서 생각하자.
// Objective-C
NSArray *array = [NSArray arrayWithObject:@“item”];
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];

// Swift
let array = [ “item” ]
var mutableArray = Array()
var는 mutable(변경가능), let은 immutable(변경불가능) 개념과 일치한다.

[관련글] Swift - 변수와 상수 그리고 타입​

특수 데이터 표현에 골뱅이가 없음

Objective-C 에선 골뱅이(@)를 자주 빼먹어서 오류가 나곤 했었는데 이젠 반대가 될지도...
// Objective-C
NSString *someString = @“Some String”;
NSArray *someArray = @[ @“item1”, @“item2”, @“item3” ];

// Swift
var someString = “Some String”
var someArray = [ “item1”, “item2”, “item3” ]
물론 이건 기쁜 소식이겠지?

id

Objective-C 에서 id 는 void * 형 타입으로써 모든 타입의 레퍼런스를 가질 수 있는 타입의 제왕이다. (물론 장난꾸러기이기도 하지만)

스위프트에서는 이와 비슷한 용도로 Any(어떠한 인스턴스도 담을 수 있는 타입) 와 AnyObject (어떠한 클래스 인스턴스나 담을 수 있는 타입) 이 있다. 물론 id 와 가장 비슷한 건 Any 타입이겠지만...

if 등에서 쓰는 조건식은 Bool 타입 강제

기존에 쓰던 C식 if 문은 잊어야 한다. 0 은 false 가 아니다. 초기화 체크가 필요하다면 Optional을 이용해야 한다.
// Objective-C
int value = 0
if (!value) { value = 10 }

// Swift - Case Error
var value = 0
if !value { value = 10 }    // Error

// Swift - with Optional
var value: Int?
if !value { value = 10 }
자 다시 정리, if 문 등 조건식이 쓰이는 데는 Bool 타입 혹은 Optional 타입이 와야한다. 그리고 Optional 상태에서 nil은 false이고 nil이 아니면 true다.

[관련글] Swift - 논리 제어문(Conditional Statements)
[관련글] Swift - 옵셔널(Optionals)

문자열 포매팅

문자열에 \()를 이용해 포매팅(Formatting) 할 수 있다.
let name = “Test Name”
let b = “You name is \(name). Is ok?”
단순 포매팅에는 편하다.

하지만 printf 스타일의 포매팅도 여전히 필요하다. 이는 NSString의 브릿지를 이용해야 할 수 있다.
let s: String = NSString(format:”%04d”, 10)
[관련글] Swift - 문자열(String)

괴물이 되어 돌아온 switch - case 문

말 그대로 괴물이 되어서 돌아왔다. break가 필요 없으면서 case에 문자열 뿐만 아니라 특수한 조건식을 넣는 등 다양한 기능을 제공한다.
var v = “test”

switch v {
case let x where x.hasSuffix(“st”):
    println(“Wow!”)
default:
    println(“No st”)
}
기존 switch - case 문의 단점을 극복하고 돌아왔기에 이제는 추천 할만한 제어구문 같다.

[관련글] Swift - 논리 제어문(Conditional Statements)

튜플

가장 좋아하는 타입인 튜플이 스위프트에도 도착했다. 멀티 리턴 등 다양한 용도에 활용해보자.
let tuples = ( “zero”, “one”, “true” )
println(tuples.0)
[관련글] Swift - 튜플(Tuple)

Assertion

기존 Objective-C 에서는 물론 C API인 assert를 사용 할 수도 있었지만 여러 문제 때문에 NSAssert()의 사용을 강제당해왔다. 이제 스위프트에서는 다시 assert() 문을 이용하면 된다.
assert(myValue == 0, “WTF! myValue is not 0!”)

코드 읽기 관련 전처리기

스위프트에 와서 몇 가지 전처리기(Preprocessor)가 바뀌었다. 예를 들어 #pragma mark 같은건 이제 사라지고 대신 주석문을 이용해 아래와 같은 식으로 남긴다.
// MARK: This is marker (instead of #pragma mark)
참고로 Xcode 6 의 첫 베타 버전에선 의미없는 그냥 주석일 뿐이다.

[관련글] Swift - 유용한 전처리기(Preprocessor)

기존 프레임워크들은 어떻게?

대부분 브릿지 매핑이 되어 있어서 비슷하게 쓸 수 있다.
// Objective-C
UIColor *color = [UIColor redColor];

// Swift
var color = UIColor.redColor() 
물론 사라진 것도 있고 바뀐 것도 있고 난감하겠지만 시간이 흐르면 문서화가 점점 갖춰질 것이니 걱정하지 말자.

상수들의 구조화

몇몇 상수들은 관련 클래스나 구조체 안으로 숨었다.
// Objective-C
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* components = [calendar components:NSYearCalendarUnit | 
                                                    NSMonthCalendarUnit | 
                                                    NSDayCalendarUnit
                                           fromDate:date];

// Swift
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(NSCalendarUnit.CalendarUnitYear |
                                     NSCalendarUnit.CalendarUnitMonth |
                                     NSCalendarUnit.CalendarUnitDay,
                                     fromDate: newValue)
전역 상수가 사라졌다고 오해하지 말고 잘 찾아보자.

참고. 위 Swift 코드에서 NSCalendarUnit은 enum(열거형) 타입이다. 그리고 해당 메소드에 이 타입 이름이 명시되어 있다. 따라서 열거형 타입 이름을 아래와 같이 생략시키는 것도 가능하다.
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitYear |
                                     .CalendarUnitMonth |
                                     .CalendarUnitDay,
                                     fromDate: newValue)

점(.)으로 시작하는 코드가 답답한(?) 사람도 없지는 않겠지만, 그래도 코드량은 제법 줄일 수 있다.

@selector?

종종 selector를 요구하는 메소드가 있는데 스위프트에는 @selector 키워는 없고 어떻게 해야 할까? 답은 그냥 문자열로 쓰는 것이다.
let button = UIButton()
button.addTarget(self, action: "buttonPressed", forControlEvents: UIControlEvents.TouchUpInside)
위 코드는 자신의 클래스에 buttonPressed 라는 메소드가 선언되어 있고 이를 셀렉터로 넘기는 코드이다. 사실 문자열로 쓰는게 좀 찝찝한데 이 문자열을 다르게 표현하면 아래와 같다.
let selector: Selector = "buttonPressed"
// 혹은
Selector("buttonPressed")
이게 자동으로 캐스팅 되어서 넘어간다는 의미이니 크게 개의치는 말자.

다만 주의해야 할 사항이 있다. 셀렉터라는 개념은 애초에 Objective-C 에서나 사용하던 KVC(Key-Value Coding) 체계라서 근본적으로 스위프트와는 맞지 않다. 이 호환성을 위해서는 반드시 사용하는 클래스를 NSObject(혹은 하위클래스)를 상속받게 만들어야 한다. 그렇지 않으면 셀렉터가 구현되어 있지 않다는 런타임 오류가 발생하게 된다.

[관련글] Objective-C에서 Swift로 넘어가기 #2
[돌아가기] 스위프트(Swift) 가이드

댓글 없음 :