ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • debugPrint와 print 알고쓰기 (feat. dump)
    Swift 2023. 5. 8. 09:21

    안녕하세요. 그린입니다🍏

    이번 포스팅에서는 debugPrint와 print에 대해 알아보려 합니다 (조금 더 나아가서 간단히 dump까지!)🙋🏻

     

    사실 많은 iOS 개발자라면 이미 익숙하고 차이도 잘 아실텐데 한번 확실히 좀 더 명확하게 왜 로깅용으로 debugPrint를 써야하는지 그리고 모든 로깅 상황에서 debugPrint를 가져가는게 좋은건지 정리해보려고 이번 포스팅의 주제로 가져와봤습니다🕺🏻

     

    그럼 우선 개념적으로 간단하게 짚고 넘어가야하니 debugPrint와 print의 개념부터 훑어보시죠!

     

    debugPrint

    우선 공식문서에서는 디버깅에 가장 적합한 텍스트 표현을 출력에 사용한다고 아주 로깅용으로 써라!라고 대놓고 강조하고 있는 느낌입니다😲

     

    선언을 보시면 아래와 같습니다.

    func debugPrint(
        _ items: Any...,
        separator: String = " ",
        terminator: String = "\n"
    )

    어디선가 많이 보신것 같지 않나요? 이후 나오겠지만 이 선언은 print와 다를게 없습니다!

    공통적으로 모든 항목들이 출력된 후 개행시켜주도록 terminator가 달려있습니다.

     

    그럼 바로 이어서 print는 어떻게 생겨먹었는지 볼까요?

     

    print

    debugPrint에서 로깅용을 강조했다면 print에서는 그냥 주어진 항목의 텍스트 표현 출력을 위해 사용한다고 해요.

    어떻게 보면 print가 조금 더 포괄적인 느낌이죠.

     

    선언은 아래와 같아요.

    func print(
        _ items: Any...,
        separator: String = " ",
        terminator: String = "\n"
    )

    debugPrint와 동일하죠?

     

    그럼 알겠으니 이 둘의 차이를 실제 로깅을 해보면서 찾아보겠습니다!

     

    debugPrint와 print의 출력 차이

    우선 간단하게 문자열을 출력해볼께요.

    let value: String = "Green is Green"
    
    debugPrint(value)
    print(value)
    
    // "Green is Green"
    // Green is Green

    debugPrint는 문자열임으로 ""가 붙어 해당 지금 로깅 출력한 친구가 String 값이라는걸 출력을 통해 알 수 있죠.

    반면 print는 그냥 그 문자열이 갖는 값 그대로를 출력합니다.

    지금은 사실 print로 출력을 해도 Green is Green이라는 값은 누가봐도 String이기에 헷갈리는게 더 어렵다고 쳐볼께요.

     

    그럼 아래와 같을때는 어떨까요?

    let value: String = "123123"
    
    print(value)
    // 123123

    이렇게 보면 실제 print를 사용해 로깅 시 해당 값이 만약 알파벳 문자열이 아니라 "123123"과 같은 숫자 문자열이라면 이게 String인지 Int값인지 헷갈릴 수 있을거에요.

     

    그럼 조금 더 나아가볼께요.

     

    아래와 같이 1~10까지의 숫자 범위를 출력할 때는 어떨까요?

    debugPrint(1...10)
    print(1...10)
    
    // ClosedRange(1...10)
    // 1...10

    debugPrint가 명확하게 어떤 타입인지 출력해주고 있습니다.

    이처럼 로깅 시에는 타입 미스매치 오류가 있을 수 있기에 확실히 타입 정보까지 준다면 더 명확할 수 있을거에요.

     

    그럼 사실 디버그 로깅을 많이 하는 통신에서는 어떤게 좀 더 이점이 있을지 살펴볼까요?

     

    let urlReq = URLRequest(url: URL(string: "https://itunes.apple.com/search?term=jack+johnson&limit=1")!)
    
    Alamofire.request(urlReq).responseJSON { (data) in
      print("Print 로깅")
      print(data)
      print("=========")
      print("debugPrint 로깅")
      debugPrint(data)
    }

    요렇게 실제 통신하여 받아온 data를 출력할때 차이를 보시죠.

     

    print 로깅의 경우 아래와 같이 실제 전달되는 data의 핵심 정보만 노출시켜 줍니다.

    SUCCESS: {
        resultCount = 1;
        results =     (
                    {
                artistId = 909253;
                artistName = "Jack Johnson";
                artistViewUrl = "https://itunes.apple.com/us/artist/jack-johnson/id909253?uo=4";
            }
        );
    }

     

    반면 debugPrint 로깅의 경우는 어떤 request였고 response로 온 상세한 정보들을 다 담아서 보내주죠.

    [Request]: GET https://itunes.apple.com/search?term=jack+johnson&limit=1
    [Response]: <NSHTTPURLResponse: 0x610000223860> { URL: https://itunes.apple.com/search?term=jack+johnson&limit=1 } { status code: 200, headers {
        "Access-Control-Allow-Origin" = "*";
        "Cache-Control" = "max-age=86345";
        Connection = "keep-alive";
        "Content-Disposition" = "attachment; filename=1.txt";
        "Content-Length" = 1783;
        "Content-Type" = "text/javascript; charset=utf-8";
        Date = "Sat, 23 Sep 2017 14:29:11 GMT";
        "Strict-Transport-Security" = "max-age=31536000";
        Vary = "Accept-Encoding";
        "X-Apple-Partner" = "origin.0";
        "X-Cache" = "TCP_MISS from a23-76-156-143.deploy.akamaitechnologies.com (AkamaiGHost/9.1.0.4-20866905) (-)";
        "X-Cache-Remote" = "TCP_MISS from a23-45-232-92.deploy.akamaitechnologies.com (AkamaiGHost/9.1.0.4-20866905) (-)";
        "X-True-Cache-Key" = "/L/itunes.apple.com/search ci2=limit=1&term=jack+johnson__";
        "apple-originating-system" = MZStoreServices;
        "apple-seq" = 0;
        "apple-timing-app" = "86 ms";
        "apple-tk" = false;
        "x-apple-application-instance" = 1000492;
        "x-apple-application-site" = NWK;
        "x-apple-jingle-correlation-key" = VEF3J3UWCHKUSGPHDZRI6RB2QY;
        "x-apple-orig-url" = "https://itunes.apple.com/search?term=jack+johnson&limit=1";
        "x-apple-request-uuid" = "a90bb4ee-9611-d549-19e7-1e628f443a86";
        "x-apple-translated-wo-url" = "/WebObjects/MZStoreServices.woa/ws/wsSearch?term=jack+johnson&limit=1&urlDesc=";
        "x-content-type-options" = nosniff;
        "x-webobjects-loadaverage" = 0;
    } }
    [Data]: 1783 bytes
    [Result]: SUCCESS: {
        resultCount = 1;
        results =     (
                    {
                artistId = 909253;
                artistName = "Jack Johnson";
                artistViewUrl = "https://itunes.apple.com/us/artist/jack-johnson/id909253?uo=4";
            }
        );
    }
    
    [Timeline]: Timeline: 
    
    {
      "Request Start Time": 527869893.013,
      "Initial Response Time": 527869893.033,
      "Request Completed Time": 527869893.034,
      "Serialization Completed Time": 527869893.035,
      "Latency": 0.020secs,
      "Request Duration": 0.021secs,
      "Serialization Duration": 0.001secs,
      "Total Duration": 0.021secs
    }

    사실 필요한 data 정보만 로깅한다면 print로도 충분하겠지만 실제 에러가 났을때 로그로 파악이 필요하다면 어떤게 누락되고 잘못되었는지 또 타임아웃은 걸리지 않았는지 등 더 상세하고 유용한 정보를 봐야할때가 많을거에요.

    이럴때는 debugPrint가 확실한 이점을 가져갈 수 있습니다.

     

    즉 정리해보자면 단순한 로깅 시 분기처리 혹은 여기서부터 로그 시작입니다~ 같은 타입 등과 같은 상세한 정보가 필요하지 않은 부분은 print가 조금 더 깔끔할 수 있고 실제 타입 및 상세한 정보가 필요한 로깅에서는 debugPrint를 사용하는게 적절할 것 같아요!

     

    이 이점 때문에 애플에서도 로깅 시에는 debugPrint를 권장하는것 같습니다.

     

    그럼 마무리로 dump라는것도 많이 보셨을것 같은데 어떨때 쓰게 될까요?

     

    dump

    dump는 mirror라는 개념을 사용해 주어진 객체의 정보를 출력해줍니다.

    쉽게 말해 객체를 조금 더 보기 좋게 가공해서 출력해줄 수 있다는것이죠.

    선언은 아래와 같아요.

    @discardableResult func dump<T>(
        _ value: T,
        name: String? = nil,
        indent: Int = 0,
        maxDepth: Int = .max,
        maxItems: Int = .max
    ) -> T

     

    이 dump를 사용할때와 print를 사용할때의 차이를 봐볼까요?

     

    struct Person{
      var name = "Green"
      var age = 10
      var footSize = 290.5
    }
    
    let green = Person()
    
    print(green)
    dump(green)
    
    // Person(name: "Green", age: 10, footSize: 290.5)
    // ▿ Project.Person
    //  - name: "Green"
    //  - age: 10
    //  - footSize: 290.5

    보시면 위 print를 사용하여 green 객체 정보를 출력하는것보다 dump를 사용한다면 조금 더 가공되어 보여주게 됩니다.

    요럴때 dump를 적절히 사용하면 좋을것 같아요.

     

    마무리

    너무나 당연하게 사용하는것들에 대해 조금 더 명확한 기준을 세우고자 한번 정리해봤습니다!

    이럴땐 이렇게 사용한다 라는 명확한 답보다는 개인적으로 기준을 잘 세우면 좋을것 같습니다🙌

     

    [참고 자료]

    https://developer.apple.com/documentation/swift/debugprint(_:separator:terminator:) 

     

    debugPrint(_:separator:terminator:) | Apple Developer Documentation

    Writes the textual representations of the given items most suitable for debugging into the standard output.

    developer.apple.com

    https://developer.apple.com/documentation/swift/print(_:separator:terminator:) 

     

    print(_:separator:terminator:) | Apple Developer Documentation

    Writes the textual representations of the given items into the standard output.

    developer.apple.com

    https://developer.apple.com/documentation/swift/dump(_:name:indent:maxdepth:maxitems:) 

     

    dump(_:name:indent:maxDepth:maxItems:) | Apple Developer Documentation

    Dumps the given object’s contents using its mirror to standard output.

    developer.apple.com

    https://stackoverflow.com/questions/41826683/print-vs-debugprint-in-swift

     

    print() vs debugPrint() in swift

    This might be a simple question but because of clear understanding between print() and debug() print in swift I am unable to understand where to use each one.

    stackoverflow.com

     

    'Swift' 카테고리의 다른 글

    @discardableResult를 왜 쓰지?  (8) 2023.06.01
    Mirror  (15) 2023.05.16
    Swift 5.8  (4) 2023.04.04
    compare과 ComparisonResult  (5) 2023.02.08
    CGFloat  (3) 2023.01.20
Designed by Tistory.