2015년 9월 1일 화요일

Swift - print 와 debugPrint 이야기

사실 얼마 전까지만 해도 debugPrint 라는 함수가 있는지 조차 몰랐었다. 뭐 이제서라도 알게 되었으니 메모도 할겸 print 와 debugPrint 에 대한 글을 써 본다.

print 함수야 다들 알 것이다. 그냥 콘솔에 문자열 찍는 함수다.
참고로 print 함수는 Swift 1.2 까지는 println 이라는 이름으로 불리었다가 Swift 2.0 부터는 print 로 이름이 바뀌었다.
debugPrint 도 비슷하게 콘솔에 로그를 남기기 위한 용도의 함수이다.

이 둘의 결정적인 차이는 문자열로 찍을 때 어떤 프로토콜을 따르냐에 있다. 일단 이해 안되더라도 아래 스크린샷을 보자. 플레이그라운드에서 이 둘을 테스트 한 결과이다.


debugPrint의 결과물은 뭔가 요상한 것들이 덧붙여져 있다.
""Hello World"\n"
"Hello World" 부분만 안쪽에 따로 따옴표로 묶여있다. 이 녀석은 debugPrint 에 직접 넘겨준 별도의 String 값이다. 그 뒷쪽에 붙은 개행문자(\n)는 debugPrint 가 알아서 붙여준 기능이다.

여기서 파악해야 할 것은 프로그래머에 의해 넘겨진 데이터를 어떤 관점에서 파악이 가능하냐이다. 응? 어려운 말인가?

CustomStringConvertible

CustomStringConvertible 이라는 프로토콜은 print 등을 이용할 때 혹은 String으로 변환할 때의 약속을 정의한 프로토콜이다. 단순하게 description 이라는 String 타입의 프로퍼티 게터(getter)를 구현하면 되는 간단한 프로토콜이다.

아래의 예제는 CustomStringConvertible 을 사용한 예제이다.
struct MyType: CustomStringConvertible {
    let value: Int
    
    var description: String {
        return "\(self.value)"
    }
}
이제 이 녀석을 이용해 시험해보자.
let v1 = MyType(value: 1)

print(v1)
// 콘솔에 "1\n" 이 찍힌다.

debugPrint(v1)
// 콘솔에 "1\n" 이 찍힌다.
print나 debugPrint문을 이용해 MyType 인스턴스를 출력시키자 description 의 내용을 자동으로 받아와서 처리한다. 여기서 print와 debugPrint 의 결과가 같다는 것을 알아두고 다음으로 넘어가자.

CustomDebugStringConvertible

이번엔 Debug 라는 이름이 붙은 StringConvertible 프로토콜이다. 앞서 본 CustomStringConvertible 과 비슷한 방법으로 사용하고 비슷한 용도로 사용된다. 하지만 이번에는 debug 라는 이름이 붙어있으니 debugPrint 와 관련이 있지 않을까 예상된다면 바로 정답이다.
struct MyType: CustomStringConvertible, CustomDebugStringConvertible {
    let value: Int
    
    var description: String {
        return "\(self.value)"
    }
    
    var debugDescription: String {
        return "MyType[\(self.value)]"
    }
}
앞의 예제에서 CustomDebugStringConvertible 을 추가로 붙였다. 이 프로토콜은 debugDescription 이라는 String 타입의 프로퍼티 게터(Getter)를 구현하기만 하면 된다.

이제 결과가 다르겠지?
let v2 = MyType(value: 2)

print(v2)
// 콘솔에 "2\n" 이 찍힌다.

debugPrint(v2)
// 콘솔에 "MyType[2]\n" 이 찍힌다.
빙고! CustomDebugStringConvertible 은 debugPrint 에서만 호출되고 있는 것을 볼 수 있다.

결론

결론 낼 꺼리가 없는것 같다. 그냥 print는 CustomStringConvertible 과 친하고 debugPrint 는 CustomDebugStringConvertible 과 친하다 정도이다.

참고로 Swift 2.0 에서 print 함수와 debugPrint 함수의 원형은 아래와 같다.
print(items: Any..., separator: String, terminator: String, toStream: &Target)

debugPrint(items: Any..., separator: String, terminator: String, toStream: &Target)
여기서 terminator 의 기본값은 "\n" 이다. 앞서 debugPrint를 이용해 "Hello World" 를 찍었을 때 "\n"이 별도로 표시되는 것을 볼 수 있는데 이 terminator의 값이 별도로 표시되도록 만들어 둔 거라고 생각하면 되겠다.

사실 쉽고 단순한 내용이다. 그저 CustomStringConvertible 의 설명을 적기엔 내용이 너무 초라하고 print 나 debugPrint 만 따로 적기에도 초라해서 이 둘을 이리저리 섞어보니 이런 글이 탄생하게 되었다. :-)

[관련글] Swift 2.0 - 그 외 사소한(?) 변화들
[관련글] 스위프트(Swift) 가이드

댓글 2개 :

김시진천재 :

xcode 오른쪽 하단 콘솔창 말하는 거죠?
거기 찍히게 실행은 어떻게 하나요? Run 해봐도 안찍히는데
시뮬레이터도 같이 실행되고 시뮬 실행안되고 찍히게 할 수 있나요?

Seorenn :

@김시진천재: 네 콘솔창 위치는 맞습니다. 만약 여기에 로그가 안찍힌다면 print() 코드가 실행이 안된거라고 생각해야 겠지요. iOS/macOS 앱 프로젝트에서 시험해 보신다면 AppDelegate 파일의 didLaunch 메소드 내에서 시험해보시는 것이 가장 간단할 것 같습니다.

시뮬레이터는 iOS 프로젝트라면 당연히 실행되어야 합니다. 만약 그게 싫다면 아이폰 등 iOS 디바이스를 직접 연결해서 해당 디바이스에서 테스트 해 보거나, 아니면 macOS용 앱 프로젝트로 만들어서 시험해 보는 방법도 있겠지만 상황에 따라 다르겠지요.