[ios] 릴리스 버전 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()입력이 좀 더 유연하므로 모든 인스턴스에서 사용할 수 없습니다. 내 코드.


답변

스위프트 5

프로젝트에서 새 파일을 만들고 다음 코드를 붙여 넣기 만하면됩니다.

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

이 함수 서명은 기본 Swift 서명과 일치하므로 프로젝트의 함수를 “덮어 씁니다”. 필요한 경우을 사용하여 원본에 계속 액세스 할 수 있습니다 Swift.print().

위의 코드를 추가 한 후에 print()는 평소와 같이 계속 사용 하면 디버그 빌드에서만 인쇄됩니다.

참고 : forEach각 항목을 인쇄하기 위해을 수행하면 바로으로 전달하는 경우 표시되는 인쇄 문 주위의 성가신 배열 대괄호가 제거 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 = " ", terminator: String = "\n")

위의 대답은 정확한 Swift 구현을 반영합니다.하지만 한 가지 이상을 인쇄하거나 구분 기호 / 종료자를 변경하지 않습니다. 그러나 누가 알겠습니까?


답변

내가 사용하는 함수는 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 메시지

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


답변

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
}