println()
디버그 빌드가 아닌 경우 Swift 코드의 모든 호출 을 전역 적으로 무시하고 싶습니다 . 이에 대한 단계별 지침을 찾을 수 없으며 지침에 감사드립니다. 전 세계적으로이 작업을 수행하거나 할 내가 모든 서라운드해야 할 수있는 방법이 println()
함께 #IF DEBUG/#ENDIF
문은?
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)
}
println()
릴리스 모드에서 실행 되지 않는다고 들었습니다 .
println
로 변경 print
. 그것이 작동하지 않는 이유는 print
정의가 Swift와 일치하지 않으므로 재정의하지 않기 때문입니다. 여러 번 언급했듯이 Swift에는 splat 연산자가 없으므로 variadic을 전달할 수 없기 때문에 약간의 문제가 있습니다. 그러나 하나의 항목에 대해 잘 작동하며 items[0]
.
Swift 4.x 업데이트 :
이제 Swift 2.0 / 3.0 및 Xcode 7/8이 베타 버전으로 출시되면서 릴리스 빌드에서 인쇄 기능을 비활성화하는 방법에 몇 가지 변경 사항이 있습니다.
위의 @matt 및 @Nate Birkholz가 언급 한 몇 가지 중요한 사항이 여전히 유효합니다.
println()
함수로 대체 한print()
#if DEBUG
매크로 를 사용하려면 값을 포함하도록 "Swift Compiler-Custom Flags -Other Flags"를 정의해야합니다.-D DEBUG
코드에서 정상적으로 함수를 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부터 ++
연산자는 더 이상 사용되지 않습니다. 이 변경 사항을 반영하기 위해 위의 스 니펫을 업데이트했습니다.
public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
저를 포함하여 이러한 모든 접근 방식의 문제점은 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())
따라서 호출이 평가되지 않고 클로저로 래핑되고 릴리스 모드에서는 전혀 평가되지 않기 때문에 비용이 많이 들지 않습니다.
@autoclosure
합니까?
print
배송 코드에 명세서 를 남기는 경향이 있지만 여기에있는 제 답변과는 다릅니다. print
문 출력은 엑스 코드에 독립적 인 릴리즈 빌드에서 콘솔로 전송되지 않습니다 있지만 아직 평가 가 비싼 또는 원치 않는 부작용이 단지의 경우 그 평가를 억제하는 방법을 알고 도움이 유지되도록.
언급했듯이, 저는 학생이고 따라하기 위해 좀 더 명확하게 정의 된 것이 필요합니다. 많은 연구 끝에 따라야 할 순서는 다음과 같습니다.
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.1 및 Xcode 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
}
디버그 빌드 설정 -D DEBUG
이 설정 되었는지 확인한 후 더 간단합니다 OTHER_SWIFT_FLAGS
.
#if !DEBUG
func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { }
#endif
XCode 8은 몇 가지 새로운 빌드 설정을 도입했습니다 .
특히 언급 된 Active Compilation Conditions
것은 기타 플래그 설정 과 유사한 방식으로 수행됩니다.
"활성 컴파일 조건"은 조건부 컴파일 플래그를 Swift 컴파일러에 전달하기위한 새로운 빌드 설정입니다.
XCode 8 (8.2.2에서 테스트 됨)에 따라 기본적으로 다음과 같이 표시됩니다.
따라서 구성없이 다음을 작성할 수 있습니다.
#if DEBUG
print("⚠️ Something weird happened")
#endif
이 접근 방식을 광범위하게 사용하는 경우이 로깅 논리를 래핑하는 클래스 / 구조 / 함수를 만드는 것이 좋습니다. 이것을 길 아래로 더 확장 할 수 있습니다.
스위프트 4 Xcode 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)"
. 내 솔루션을 좋아하길 바래
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)
나는 이것을 사용하여 결국 :
#if DEBUG
func dLog(_ item: @autoclosure () -> Any, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
print("\(Date()) [\((file as NSString).lastPathComponent):\(line) \(function)] \(item())")
}
#else
func dLog(_ item: @autoclosure () -> Any) {}
#endif
매우 간결하고 유용한 정보 (타임 스탬프, 빠른 파일 이름, 코드 줄, 함수 이름)를 인쇄하고 적어도 내 테스트에서 16 진수 편집기에서 열 때 응용 프로그램 바이너리 파일에서 로깅 된 문자열을 찾을 수 없습니다.
더 간단하게 : 어설 션이 릴리스 빌드에서 제거되고 거기에서만 인쇄를 호출한다는 사실을 활용하십시오. 릴리스를 위해 빌드 할 때 비어 있으므로 모든 로그 호출 (예, 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에서 새 코드를 병합하기 시작했습니다. 그래서 Swift 아래 솔루션에서 저에게 효과가 있었으므로 해당 코드를 My Swift 상수 파일에 추가했습니다.
func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
#if DEBUG
items.forEach {
Swift.print($0, separator: separator, terminator: terminator)
}
#endif
}