development

릴리스 버전 iOS Swift의 경우 println () 제거

big-blog 2020. 10. 13. 08:06
반응형

릴리스 버전 iOS Swift의 경우 println () 제거


println()디버그 빌드에 있지 않은 경우 Swift 코드의 모든 호출 을 전역 적으로 무시하고 싶습니다 . 이에 대한 강력한 단계별 지침을 찾을 수 없으며 지침에 감사드립니다. 전 세계적으로이 작업을 수행하거나 할 내가 모든 서라운드해야 할 수있는 방법이 println()함께 #IF DEBUG/#ENDIF문은?


가장 간단한 방법은 Swift의 앞에 자신 만의 전역 함수를 배치하는 것입니다 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
}

EDIT Swift 2.0 println에서 print. 불행히도 이제 가변적 인 첫 번째 매개 변수가 있습니다. 이것은 멋지지만 Swift에는 "splat"연산자가 없기 때문에 쉽게 재정의 할 수 없으므로 코드에서 variadic을 전달할 수 없습니다 (문자 그대로 만 생성 할 수 있음). 그러나 일반적으로 그렇듯이 하나의 값만 인쇄하는 경우 작동하는 축소 버전을 만들 수 있습니다.

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 DEBUG매크로 를 사용하려면 "Swift Compiler-Custom Flags -Other Flags"값을 포함하도록 정의해야합니다.-D DEBUG

  3. 코드에서 정상적으로 함수를 Swift.print()사용할 수 있도록 전역 범위에서 함수를 재정의하는 것이 좋지만 print()디버그가 아닌 빌드의 출력은 제거됩니다. 다음은 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
    }
    

참고 : 여기서는 기본 구분 기호를 공백으로 설정하고 기본 종결자를 개행 문자로 설정했습니다. 원하는 경우 프로젝트에서 다르게 구성 할 수 있습니다.

도움이 되었기를 바랍니다.

최신 정보:

일반적으로이 함수를 전역 범위에 두는 것이 바람직하므로 Swift의 print함수 앞에 위치 합니다. 이를 구성하는 가장 좋은 방법은이 함수를 전역 범위에 배치 할 수있는 프로젝트 (예 : DebugOptions.Swift)에 유틸리티 파일을 추가하는 것입니다.

Swift 3부터 ++연산자는 더 이상 사용되지 않습니다. 이 변경 사항을 반영하기 위해 위의 스 니펫을 업데이트했습니다.


저를 포함하여 이러한 모든 접근 방식의 문제는 print인수 평가의 오버 헤드를 제거하지 않는다는 것 입니다. 어떤 것을 사용하든 비용이 많이 듭니다.

print(myExpensiveFunction())

유일한 해결책은 조건부 컴파일에서 실제 인쇄 호출을 래핑하는 DEBUG것입니다 (디버그 빌드에만 정의되어 있다고 가정합시다 ).

#if DEBUG
print(myExpensiveFunction())
#endif

그뿐 아니라 myExpensiveFunction릴리스 빌드에서 호출되는 것을 방지 합니다.

그러나 autoclosure 를 사용하여 평가를 한 단계 뒤로 밀어 낼 수 있습니다 . 따라서 다음과 같이 내 솔루션 (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 프로젝트 창 왼쪽의 파일 탐색기 상단에있는 프로젝트 이름을 클릭합니다. 프로젝트 이름, 빌드 대상 수 및 iOS SDK 버전이있는 행입니다.

Build Settings 탭을 선택하고 하단 근처 에있는 " Swift Compiler-Custom Flags "섹션으로 스크롤하십시오 . 섹션을 확장하려면 기타 플래그 옆에있는 아래쪽 화살표를 클릭합니다 .

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

텍스트 필드에 텍스트를 입력하고 Return 키-D DEBUG눌러 행을 커밋합니다.

프로젝트에 새 Swift 파일을 추가하십시오. 파일에 대한 사용자 정의 클래스를 만들려고하므로 다음 줄을 따라 텍스트를 입력합니다.

class Log {

  var intFor : Int

  init() {
    intFor = 42
   }

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

오늘 Xcode에서 클래스를 수락하는 데 문제가 있었기 때문에 init가 필요 이상으로 더 무거울 수 있습니다.

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

   let logFor = Log()

이제의 모든 인스턴스 println()logFor.DLog(). 출력에는 행이 호출 된 함수의 이름도 포함됩니다.

클래스 함수 내에서 해당 클래스의 클래스 함수로 함수의 복사본을 만들지 않는 한 함수를 호출 할 수 없으며 println()입력에 대해 약간 더 유연하므로 모든 인스턴스에서 사용할 수 없습니다. 내 코드.


내가 사용하는 함수는 Swift 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
    }

다음은 생성되는 출력의 예입니다.

출력 스크린 샷

설명:

  • 녹색 확인 표시는 콘솔에서 인쇄 (gLog) 메시지를 빠르게 볼 수 있도록하는 데 사용됩니다.이 메시지는 때때로 다른 메시지의 바다에서 손실 될 수 있습니다.

  • 시간 / 날짜 스탬프

  • 실행중인 스레드-제 경우에는 MainThread (UI라고 부름)이거나 MainThread (백그라운드 스레드의 경우 BG라고 함)가 아닙니다.

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

  • gLog 메시지가있는 파일 내의 기능

  • gLog 메시지의 줄 번호

  • 인쇄하려는 실제 gLog 메시지

이것이 다른 사람에게 유용하기를 바랍니다!


스위프트 4.2

아래 코드는 저에게 완벽하게 작동합니다.

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

이 함수는 기본 Swift 인쇄를 미러링하므로 동일한 방식으로 사용할 수 있습니다 print("hello world")(구분자 또는 종결 자 매개 변수를 입력 할 필요 없음). 또한 이와 같이 각 항목을 인쇄하면 .NET으로 items직접 전달하면 표시되는 인쇄 문 주위에 성가신 배열 대괄호가 제거 됩니다 Swift.print().

Swift를 처음 접하는 사람이라면 도대체 무엇인지 궁금 할 것 $0입니다. forEach블록에 전달 된 첫 번째 인수를 나타냅니다 . forEach문은 다음과 같이 작성할 수 있습니다 :

items.forEach { item in
    Swift.print(item, separator: separator, terminator: terminator)        
}

마지막으로 관심이 있다면 Swift 선언은 print다음과 같습니다.

public func print(_ items: Any..., separator: String = default, terminator: String = default)

문서는 또한 기본 구분 기호가 단일 공백 ​​( " ")이고 기본 종결자는 줄 바꿈 ( "\n")이므로 위의 대답은 정확한 Swift 구현을 반영 한다고 말합니다. 하지만 두 개 이상을 인쇄하거나 구분 기호 / 종료자를 변경하지 않습니다. 그러나 누가 알겠습니까?


Swift 2.1Xcode 7.1.1로 테스트 됨

Swift 컴파일러에 의해 빈 함수가 제거 되었다는 것을 알게되면 릴리스 버전에서 모든 print 문을 제외하는 쉬운 방법이 있습니다 .

사이드 노트 : 오브젝티브 C의 시대에, 내 대답에 설명 된 것처럼 컴파일러에서 쫓겨 전에 NSLog 문을 제거하는 데 사용할 수있는 사전 파서 있었다 여기가 . 그러나 Swift에는 더 이상 pre-parser가 없기 때문에이 접근법은 더 이상 유효하지 않습니다.

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

필요에 따라 기능을 조정할 수 있으며 개선을위한 제안을 환영합니다!

// 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
}

다음은 컴파일러 플래그를 설정하는 곳입니다.

여기에 이미지 설명 입력

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

   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
}

XCode 8은 몇 가지 새로운 빌드 설정을 도입했습니다 .
특히 언급 된 Active Compilation Conditions것은 Other Flags 설정 과 유사한 방식으로 수행됩니다.

"활성 컴파일 조건"은 조건부 컴파일 플래그를 Swift 컴파일러에 전달하기위한 새로운 빌드 설정입니다.

XCode 8 (8.2.2에서 테스트 됨)에 따라 기본적으로 다음과 같이 표시됩니다.

여기에 이미지 설명 입력

So without any config you can write the following:

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

I strongly recommend you that if you use this approach extensively create a class/struct/function that wraps this logging logic. You may want to extend this further down the road.


Even simpler, after making sure -D DEBUG is set for the OTHER_SWIFT_FLAGS Debug build settings:

#if !DEBUG
    func println(object: Any) {}
    func print(object: Any){}
#endif

In Swift 2/Xcode 7 you no longer need/use println but you may want to add lines for:

func print(_ items: Any..., separator separator: String = default, terminator terminator: String = default)

Swift 4 Xcode 10.0

maybe you could use this

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

The reason of using @autoclosure is that if you pass a function as the message parameter, the function will be called only in debug mode, it will cause a performance hit.

Swift.print(_ items: Any..., separator: String = default, terminator: String = default)함수 와 달리 내 솔루션에는 하나의 매개 변수 만 있습니다. 대부분의 경우 인쇄 함수는 콘솔에 정보 만 표시하므로 여러 매개 변수를 전달하지 않고 매개 변수를 String :으로 변환 할 수 있습니다 "\(param1)"+"\(param2)". 내 솔루션을 좋아하길 바래


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 

}

내 솔루션을 위해 간단하게 만듭니다.

import UIKit

class DLog: NSObject {

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

   }

}

그런 다음 그것을 보여주기 위해

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

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

반응형