programing

릴리스 버전 iOS Swift에 대해 println()을 제거합니다.

closeapi 2023. 11. 2. 21:43
반응형

릴리스 버전 iOS Swift에 대해 println()을 제거합니다.

전 세계적으로 모든 것을 무시하고 싶습니다.println()내가 디버그 빌드에 있지 않으면 Swift 코드를 호출합니다.이에 대한 강력한 지침을 단계별로 찾을 수 없으며 안내해 주시면 감사하겠습니다.이것을 전세계적으로 할 수 있는 방법이 있습니까, 아니면 모든 것을 둘러쌀 필요가 있습니까?println()와 함께#IF DEBUG/#ENDIF진술?

가장 간단한 방법은 스위프트의 글로벌 기능을 앞에 두는 것입니다.println:

func println(object: Any) {
    Swift.println(object)
}

로깅을 중지할 시간이 되면 해당 기능의 본문을 주석으로 달기만 하면 됩니다.

func println(object: Any) {
    // Swift.println(object)
}

또는 조건을 사용하여 자동으로 만들 수도 있습니다.

func println(object: Any) {
    #if DEBUG
        Swift.println(object)
    #endif
}

스위프트 2.0에서 편집println로 변경됩니다.print. 불행히도 이제는 가변 첫 번째 매개 변수가 있습니다. 멋지지만 Swift에는 "스플랫" 연산자가 없으므로 코드의 가변을 전달할 수 없기 때문에 쉽게 재정의할 수 없습니다(문자 그대로만 만들 수 있음).그러나 일반적으로 한 가지 값만 인쇄하는 경우에는 축소된 버전을 만들 수 있습니다.

func print(items: Any..., separator: String = " ", terminator: String = "\n") {
    Swift.print(items[0], separator:separator, terminator: terminator)
}

Swift 3에서는 첫 번째 파라미터의 외부 라벨을 억제해야 합니다.

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    Swift.print(items[0], separator:separator, terminator: terminator)
}

Swift 4.x용으로 업데이트됨:

Swift 2.0/3.0과 Xcode 7/8이 베타 버전이 아닌 상태에서 릴리스 빌드에서 인쇄 기능을 비활성화하는 방법에 약간의 변화가 있습니다.

위에서 @matt 와 @Nate Birkholz 가 언급한 몇가지 중요한 사항들은 여전히 유효합니다.

  1. println()기능이 대체되었습니다.print()

  2. 사용방법#if DEBUGmacro 값을 포함하려면 "Swift Compiler - Custom Flags - Other Flags"를 정의해야 합니다.-D DEBUG

  3. 나는 그것을 우선하는 것을 추천합니다.Swift.print()를 사용할 수 있도록 전역 범위에서 기능합니다.print()코드에서는 정상적으로 작동하지만 debug가 아닌 빌드의 경우 출력이 제거됩니다.Swift 2.0/3.0에서 이 작업을 수행하기 위해 전역 범위에서 추가할 수 있는 기능 서명은 다음과 같습니다.

    func print(items: Any..., separator: String = " ", terminator: String = "\n") {
    
        #if DEBUG
    
        var idx = items.startIndex
        let endIdx = items.endIndex
    
        repeat {
            Swift.print(items[idx], separator: separator, terminator: idx == (endIdx - 1) ? terminator : separator)
            idx += 1
        }
        while idx < endIdx
    
        #endif
    }
    

참고: 기본 구분 기호는 공백으로 설정하고 기본 종단 기호는 새 줄로 설정했습니다.원하는 경우 프로젝트에서 이를 다르게 구성할 수 있습니다.

도움이 되길 바랍니다.

업데이트:

일반적으로 이 기능을 전역 범위에 두는 것이 좋습니다. 그러면 스위프트의 기능 앞에 놓이게 됩니다.print기능.이를 구성하는 가장 좋은 방법은 DebugOptions와 같은 유틸리티 파일을 프로젝트에 추가하는 것입니다.Swift) 이 함수를 전역 범위에 배치할 수 있습니다.

스위프트 3 기준으로++연산자가 더 이상 사용되지 않습니다.이 변경 사항을 반영하기 위해 위의 스니펫을 업데이트했습니다.

저를 포함한 이 모든 접근법의 문제점은 이 접근법이 평가하는 오버헤드를 제거하지 못한다는 것입니다.print논쟁들.어떤 제품을 사용하든 비용이 많이 들 것입니다.

print(myExpensiveFunction())

적절한 유일한 해결책은 실제 인쇄 콜을 조건부 컴파일로 포장하는 것입니다(다음 가정).DEBUG디버그 빌드에 대해서만 정의됨):

#if DEBUG
print(myExpensiveFunction())
#endif

그것만이, 오직 그것만이,myExpensiveFunction릴리스 빌드에서 호출된 것으로부터.

그러나 자동 폐쇄를 사용하여 평가를 한 단계 뒤로 밀 수 있습니다.따라서 제 솔루션(Swift 3)을 다음과 같이 다시 작성할 수 있습니다.

func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") {
    #if DEBUG
    Swift.print(item(), separator: separator, terminator: terminator)
    #endif
}

이것은 보통 한 가지만 인쇄하는 경우에만 문제를 해결합니다. 이것은 보통 사실입니다.그 이유는item()릴리스 모드에서 호출되지 않습니다.print(myExpensiveFunction())따라서 통화는 평가되지 않고 종료 상태로 포장되며 릴리스 모드에서는 전혀 평가되지 않기 때문에 비용 부담이 중단됩니다.

쉬운 답 - Xcode 14, Swift 5

프로젝트에 새 파일을 만들고 다음 코드에 붙여넣습니다.

import Foundation

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    #if DEBUG
    Swift.print(items, separator: separator, terminator: terminator)
    #endif
}

이 함수 서명은 기본 Swift와 일치합니다.print따라서 프로젝트 전체에 걸쳐 함수를 덮어씁니다.필요한 경우 다음을 사용하여 원본에 액세스할 수 있습니다.Swift.print().

위의 코드를 추가했으면 계속 사용하십시오.print()평소와 다름없이 디버그 빌드로만 인쇄됩니다.

말씀하신 것처럼, 저는 학생이기 때문에 조금 더 명확하게 정의된 것들이 뒤따라야 합니다.많은 연구 끝에 제가 따라야 할 순서는 다음과 같습니다.

Xcode 프로젝트 창의 왼쪽에 있는 File Navigator(파일 탐색기) 상단에 있는 프로젝트 이름을 클릭합니다.프로젝트 이름과 빌드 대상이 몇 개인지, iOS SDK 버전이 적혀있는 라인입니다.

Build Settings(빌드 설정) 탭을 선택하고 아래쪽 가까운 "Swift Compiler(스위프트 컴파일러) - Custom Flags(사용자 지정 플래그)" 섹션으로 스크롤합니다.기타 플래그 옆에 있는 아래쪽 화살표를 클릭하여 섹션을 확장합니다.

디버그 행을 클릭하여 선택합니다.마우스 커서를 선 오른쪽에 놓고 두 번 클릭합니다.목록 보기가 나타납니다.목록 보기의 왼쪽 하단에 있는 + 버튼을 클릭하여 값을 추가합니다.텍스트 필드가 활성화됩니다.

텍스트 필드에 텍스트를 입력합니다.-D DEBUGReturn을 눌러 줄을 커밋합니다.

새 Swift 파일을 프로젝트에 추가합니다.파일에 대한 사용자 지정 클래스를 만들 수 있으므로 다음 행에 텍스트를 입력합니다.

class Log {

  var intFor : Int

  init() {
    intFor = 42
   }

  func DLog(message: String, function: String = __FUNCTION__) {
    #if DEBUG
      println("\(function): \(message)")
    #endif
  }
}

오늘 Xcode에서 수업을 받는 데 어려움을 겪고 있어서 필요 이상으로 무게가 많이 나갈 수도 있습니다.

이제 새로운 사용자 지정 기능을 대신 사용하려는 클래스에서 사용자 지정 클래스를 참조해야 합니다.println()적용 가능한 모든 클래스의 속성으로 추가:

   let logFor = Log()

이제 모든 인스턴스(instance)를 교체할 수 있습니다.println()와 함께logFor.DLog(). 출력에는 회선이 호출된 함수의 이름도 포함됩니다.

참고로 클래스 기능 내부에서 클래스 기능으로 기능을 복사하지 않으면 해당 기능을 호출할 수 없습니다.println()입력이 좀 더 유연해서 코드의 모든 경우에 사용할 수는 없었습니다.

스위프트 3에서 완벽하게 작동하는 기능은 다음과 같습니다.

func gLog<T>( _ object: @autoclosure() -> T, _ file: String = #file, _ function: String = #function, _ line: Int = #line)
    {
    #if DEBUG
        let value = object()
        let stringRepresentation: String

        if let value = value as? CustomDebugStringConvertible
            {
            stringRepresentation = value.debugDescription
            }
        else if let value = value as? CustomStringConvertible
            {
            stringRepresentation = value.description
            }
        else
            {
            fatalError("gLog only works for values that conform to CustomDebugStringConvertible or CustomStringConvertible")
            }

        let fileURL = NSURL(string: file)?.lastPathComponent ?? "Unknown file"
        let queue = Thread.isMainThread ? "UI" : "BG"
    let gFormatter = DateFormatter()
    gFormatter.dateFormat = "HH:mm:ss:SSS"
        let timestamp = gFormatter.string(from: Date())

        print("✅ \(timestamp) {\(queue)} \(fileURL) > \(function)[\(line)]: " + stringRepresentation + "\n")
    #endif
    }

생성되는 출력의 예는 다음과 같습니다.

screenshot of output

설명:

  • 녹색 체크 표시는 콘솔에서 인쇄(gLog) 메시지를 빠르게 볼 수 있도록 하는데 사용되며, 다른 메시지가 바다에 잠겨 있을 수도 있습니다.

  • 시간/날짜 도장

  • 실행 중인 스레드 - MainThread(UI라고 함) 또는 MainThread(배경 스레드의 경우 BG라고 함) 중 하나입니다.

  • gLog 메시지가 있는 파일의 이름

  • gLog 메시지가 있는 파일 내의 함수

  • gLog 메시지의 행 번호

  • 출력하고자 하는 실제 gLog 메시지

이것이 다른 누군가에게 유용하기를 바랍니다!

Swift 2.1Xcode 7.1.1로 테스트됨

스위프트 컴파일러에 의해 함수가 제거되는 것을 알게 되면 릴리스 버전에서 모든 인쇄문을 제외할 수 있는 쉬운 방법이 있습니다.

참고 사항: Objective-C 시대에는 컴파일러가 시작하기 전 NSLog 문을 제거하는 데 사용할 수 있는 pre-parser가 있었습니다. 여기 제 답변에서 설명한 것처럼 말입니다.그러나 Swift는 더 이상 사전 파서가 없기 때문에 이러한 접근 방식은 더 이상 유효하지 않습니다.

릴리스 빌드에서 로그를 제거할 필요 없이 쉽게 구성할 수 있는 고급 로그 기능으로 오늘날 사용하고 있습니다.또한 서로 다른 컴파일러 플래그를 설정하여 필요에 따라 기록되는 정보를 조정할 수 있습니다.

필요에 따라 기능을 조정할 수 있습니다. 개선을 위한 어떤 제안이라도 환영합니다!

// Gobal log() function
//
// note that empty functions are removed by the Swift compiler -> use #if $endif to enclose all the code inside the log()
// these log() statements therefore do not need to be removed in the release build !
//
// to enable logging
//
// Project -> Build Settings -> Swift Compiler - Custom flags -> Other Swift flags -> Debug
// add one of these 3 possible combinations :
//
//      -D kLOG_ENABLE
//      -D kLOG_ENABLE -D kLOG_DETAILS
//      -D kLOG_ENABLE -D kLOG_DETAILS -D kLOG_THREADS
//
// you can just call log() anywhere in the code, or add a message like log("hello")
//
func log(message: String = "", filePath: String = #file, line: Int = #line, function: String = #function) {
            #if kLOG_ENABLE

            #if kLOG_DETAILS

            var threadName = ""
            #if kLOG_THREADS
                threadName = NSThread.currentThread().isMainThread ? "MAIN THREAD" : (NSThread.currentThread().name ?? "UNKNOWN THREAD")
                threadName = "[" + threadName + "] "
            #endif

            let fileName = NSURL(fileURLWithPath: filePath).URLByDeletingPathExtension?.lastPathComponent ?? "???"

            var msg = ""
            if message != "" {
                msg = " - \(message)"
            }

            NSLog("-- " + threadName + fileName + "(\(line))" + " -> " + function + msg)
        #else
            NSLog(message)
        #endif
    #endif
}

컴파일러 플래그를 설정할 수 있는 위치는 다음과 같습니다.

enter image description here

모든 플래그가 켜져 있는 출력 예는 다음과 같습니다.

   2016-01-13 23:48:38.026 FoodTracker[48735:4147607] -- [MAIN THREAD] ViewController(19) -> viewDidLoad() - hello

log()가 있는 코드는 다음과 같습니다.

    override func viewDidLoad() { log("hello")
    super.viewDidLoad()

   // Handle the text field's user input through delegate callbacks
   nameTextField.delegate = self
}

더 간단하게, 확실히 한 후에-D DEBUG준비되어 있습니다.OTHER_SWIFT_FLAGS디버그 빌드 설정:

#if !DEBUG
    func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { }
#endif

X코드 8은 몇 가지 새로운 빌드 설정을 도입했습니다.
특히 다음과 같이 언급된 것.Active Compilation Conditions기타 플래그 설정과 유사한 방식으로 수행합니다.

"Active Compilation Conditions"는 조건부 컴파일 플래그를 스위프트 컴파일러에 전달하기 위한 새로운 빌드 설정입니다.

XCode 8(8.3.2에서 테스트)에 따라 기본적으로 다음을 얻을 수 있습니다.

enter image description here

따라서 아무런 구성 없이 다음을 작성할 수 있습니다.

#if DEBUG
    print("⚠️ Something weird happened")
#endif

이 방법을 광범위하게 사용할 경우 이 로깅 로직을 래핑하는 클래스/구조/함수를 생성할 것을 강력히 권장합니다.이것을 앞으로 더 확장하는 것이 좋을 것입니다.

Varun Naharia는 지금까지 더 나은 해결책을 가지고 있습니다.그의 대답과 리베라의...

  1. 창조하다, 창안-D DEBUG컴파일러 명령에 플래그를 지정하고 설정을 만듭니다.
  2. 다음 코드를 추가합니다.

    #if !DEBUG
     public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    }
    #endif
    

이 코드는 다음과 같이 변환됩니다.print아무 것도 아닌 것처럼 말입니다

스위프트 4 X코드 10.0

당신이 이걸 사용할 수도 있습니다.

func dPrint(_ message: @autoclosure () -> Any) {
    #if DEBUG
    print(message())
    #endif
}

사용이유@autoclosure메시지 매개 변수로 함수를 전달하면 해당 함수가 디버그 모드에서만 호출되므로 성능 히트가 발생합니다.

과는 달리Swift.print(_ items: Any..., separator: String = default, terminator: String = default)함수, 제 솔루션에는 파라미터가 하나밖에 없습니다. 대부분의 경우 인쇄 함수가 콘솔에 정보만 표시하기 때문에 여러 개의 파라미터를 전달하지 않고, 파라미터를 String으로 변환할 수 있기 때문입니다."\(param1)"+"\(param2)",그렇죠?내 해결책이 마음에 드셨으면 좋겠습니다.

나의 해결책은 간단합니다.

import UIKit

class DLog: NSObject {

   init(title:String, log:Any) {
       #if DEBUG
           print(title, log)
       #endif

   }

}

보여주기 위해 전화만 하면 됩니다.

_ = DLog(title:"any title", log:Any)

중단점을 사용하여 평가 후 계속 진행하도록 설정하고 중단점에 인쇄 메시지를 작성할 수도 있습니다!

enter image description here

당신은 정의할 수 있습니다.debug_println그 내용은 대략 다음과 같습니다.

#if DEBUG
  println()
#endif

내 솔루션은 수업 전에 AppDelegate에서 이 코드를 사용하는 것입니다.

// Disable console log in live app
#if !arch(x86_64) && !arch(i386)
    public func debugPrint(items: Any..., separator: String = " ", terminator: String = "\n") {

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

    }
#endif

class AppDelegate: UIResponder, UIApplicationDelegate {
// App Delegate Code 

}

더욱 간단합니다. 릴리스 빌드에서 assert를 제거하고 인쇄만 호출한다는 사실을 활용합니다.이렇게 하면 릴리스를 위해 작성할 때 비어 있으므로 모든 로그 호출(예, Log.da에 대한 호출)이 제거됩니다.

하지만 릴리즈 빌드를 위해 프린트가 제거된다고 들었는데, 문서로 찾을 수 없었습니다.그래서 지금은 이런 걸 쓰고 있어요.Log아래. 저는 GitHub에서 이모티콘(가독성을 위해)과 로그 주제(일관성을 위해)가 포함된 좀 더 충실한 버전을 가지고 있습니다.

https://github.com/Gatada/JBits/blob/master/Project/Utility/Log.swift

public enum Log {

    /// A date formatter used to create the timestamp in the log.
    ///
    /// This formatter is only created if it is actually used, reducing the
    /// overhead to zero.
    static var formatter: DateFormatter?

    // MARK: - API

    /// Call to print message in debug area.
    ///
    /// Asserts are removed in release builds, which make
    /// the function body empty, which caused all calls to
    /// be removed as well.
    ///
    /// Result is zero overhead for release builds.
    public static func da(_ message: String) {
        assert(debugAreaPrint(message))
    }

    // MARK: - Helpers

    /// The function that actually does the printing. It returns `true` to
    /// prevent the assert from kicking in on debug builds.
    private static func debugAreaPrint(_ message: String) -> Bool {
        print("\(timestamp) - \(message)")
        return true
    }

    /// Creates a timestamp used as part of the temporary logging in the debug area.
    static private var timestamp: String {

        if formatter == nil {
            formatter = DateFormatter()
            formatter!.dateFormat = "HH:mm:ss.SSS"
        }

        let date = Date()
        return formatter!.string(from: date)
    }
}

코드명:

Log.da("This is only handled in a debug build.")

디버그 빌드를 실행할 만 Xcode 디버그 영역에 표시됩니다.

13:36:15.047 - 디버그 빌드에서만 처리됩니다.

내 프로젝트는 Objective C에서 개발되었지만 작년부터 Swift에서 새로운 코드를 병합하기 시작하여 아래 솔루션이 효과가 있었고 My Swift 상수 파일에 해당 코드를 추가했습니다.

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    #if DEBUG
    items.forEach {
        Swift.print($0, separator: separator, terminator: terminator)
    }
    #endif
}

이것은 저에게 적합합니다. (프로젝트에서 글로벌 기능으로 추가)

func print(_ items: Any...) {
    #if DEBUG
        Swift.print(items[0])
    #endif
}

언급URL : https://stackoverflow.com/questions/26913799/remove-println-for-release-version-ios-swift

반응형