Loại bỏ println () cho phiên bản phát hành iOS Swift


84

Tôi muốn bỏ qua toàn cầu tất cả các println()lệnh gọi trong mã Swift của mình nếu tôi không ở trong bản dựng Gỡ lỗi. Tôi không thể tìm thấy bất kỳ hướng dẫn từng bước rõ ràng nào cho việc này và tôi sẽ đánh giá cao hướng dẫn. là có một cách để làm điều này trên toàn cầu, hay tôi cần phải bao quanh mỗi println()với #IF DEBUG/#ENDIFbáo cáo?



6
in không còn đầu ra trong Bảng điều khiển thiết bị mà xuất hiện trong bảng điều khiển trình gỡ lỗi..Do đó không cần xóa đối với phiên bản phát hành.
Anish Parajuli 웃

1
Kể từ Xcode 8 và swift 3, tôi không thấy bản in trong bảng điều khiển ở chế độ phát hành.
CiNN

Câu trả lời:


101

Cách đơn giản nhất là đặt hàm toàn cục của riêng bạn trước Swift println:

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

Khi đến lúc ngừng ghi nhật ký, chỉ cần nhận xét phần nội dung của hàm đó:

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

Hoặc bạn có thể làm cho nó tự động bằng cách sử dụng điều kiện:

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

CHỈNH SỬA Trong Swift 2.0 printlnđược thay đổi thành print. Thật không may, bây giờ nó có một tham số đầu tiên khác nhau; điều này thật tuyệt, nhưng nó có nghĩa là bạn không thể dễ dàng ghi đè nó vì Swift không có toán tử "splat" nên bạn không thể chuyển một biến thể trong mã (nó chỉ có thể được tạo theo nghĩa đen). Nhưng bạn có thể tạo một phiên bản rút gọn hoạt động nếu, như thường lệ, bạn chỉ in một giá trị:

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

Trong Swift 3, bạn cần loại bỏ nhãn bên ngoài của tham số đầu tiên:

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

3
Giải pháp tốt, cảm ơn. Tôi đã được thông báo rằng trong iOS (nhưng không phải OS X), println()không được thực thi ở chế độ phát hành.
Nate Birkholz

13
@NateBirkholz Không, điều đó vô nghĩa. (Said ông, sau khi kiểm tra để chắc chắn!)
mờ

Trong phiên bản swift 2, với chức năng được đổi tên thành in, liệu bạn có cơ hội để func khớp không? Ngoài ra, bạn sẽ xác định điều này trên toàn cầu như thế nào? Tôi đã thử đặt nó bên ngoài lớp học của mình trong AppDelegate và nó không bao giờ được gọi mặc dù tôi có một triệu cuộc gọi print (). Đây là những gì tôi đã thử: func print (object: Any) {Swift.print (object)}
Charlie

@Charlie Có, tôi vẫn đang sử dụng nó với sự printlnthay đổi thành print. Lý do nó không hoạt động với bạn là printđịnh nghĩa của bạn không khớp với Swift, vì vậy bạn không nên ghi đè nó. Có một vấn đề nhỏ bởi vì, như đã được nhận xét nhiều lần, Swift không có toán tử biểu tượng, vì vậy bạn không thể vượt qua biến thể. Nhưng nó hoạt động tốt cho một mục, mà bạn có thể vượt qua items[0].
matt

2
Một lưu ý ở đây nếu bạn đang chèn các câu lệnh nhật ký này vào các phần mã hiệu suất cao: Swift sẽ vẫn dành thời gian thực hiện nội suy chuỗi và các tham số hiển thị để chuyển cho hàm, ngay cả khi chúng không được sử dụng. Cách duy nhất mà tôi thấy để thực sự loại bỏ có điều kiện các câu lệnh là đặt vị ngữ của chúng trên một lá cờ. ví dụ if (log) {print (..)} ở mỗi vị trí mà chúng được sử dụng.
Pat Niemeyer

46

Đã cập nhật cho Swift 4.x:

Với Swift 2.0 / 3.0 và Xcode 7/8 hiện đã hết phiên bản beta, đã có một số thay đổi về cách bạn tắt chức năng in trong các phiên bản phát hành.

Có một số điểm quan trọng được @matt và @Nate Birkholz đề cập ở trên vẫn còn giá trị.

  1. Các println()chức năng đã được thay thế bởiprint()

  2. Để sử dụng #if DEBUG macro thì bạn phải xác định "Trình biên dịch Swift - Cờ tùy chỉnh-Cờ khác" để chứa giá trị-D DEBUG

  3. Tôi khuyên bạn nên ghi đè Swift.print()hàm trong phạm vi toàn cục để bạn có thể sử dụng print()hàm như bình thường trong mã của mình, nhưng nó sẽ xóa đầu ra cho các bản dựng không gỡ lỗi. Đây là một chữ ký hàm mà bạn có thể thêm ở phạm vi toàn cầu để thực hiện việc này trong 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
    }
    

Lưu ý: Chúng tôi đã đặt dấu phân tách mặc định là khoảng trắng ở đây và dấu chấm dứt mặc định là một dòng mới. Bạn có thể cấu hình điều này theo cách khác trong dự án của mình nếu bạn muốn.

Hi vọng điêu nay co ich.

Cập nhật:

Thường nên đặt hàm này ở phạm vi toàn cục, để nó nằm trước hàm của Swift print. Tôi thấy rằng cách tốt nhất để tổ chức việc này là thêm một tệp tiện ích vào dự án của bạn (như DebugOptions.Swift), nơi bạn có thể đặt chức năng này ở phạm vi toàn cầu.

Kể từ Swift 3, ++toán tử sẽ không được dùng nữa. Tôi đã cập nhật đoạn mã ở trên để phản ánh thay đổi này.


1
Tôi xin lỗi, nhưng để đặt chức năng ở đâu?
DàChún

@ User9527 Có thể bạn muốn đặt cái này ở đâu đó trong phạm vi toàn cầu, để nó có thể truy cập được trong suốt dự án của bạn. Trong các dự án của mình, tôi thêm một tệp nhanh tiện ích (DebugOptions.swift hoặc một cái gì đó tương tự) và đặt hàm này trong phạm vi toàn cục (tức là không phải trong một lớp kèm theo).
Glavid

Bạn có thể xác nhận rằng kể từ phiên bản Swift-Xcode hiện tại, câu lệnh in sẽ không còn xuất ra bảng điều khiển thiết bị mà không cần đặt căn hộ -D Debug không? Ít nhất đó là những gì tôi đã thử nghiệm ngày hôm nay.
user523234

1
Tính đến Swift 3, người ta có thể có được một chút ngắn gọn hơn bằng cách thêm một dấu gạch dưới vào đầu danh sách các đối số: "in (_ các mặt hàng ..."
Jonathan Zhan

7
Vì vậy, tôi đã tìm kiếm tham chiếu của bản in (được sử dụng trong didFinishLaunching ...) và nó chỉ tôi đến hàm in ban đầu Swift. Đưa đó và @ bình luận JonathanZhan của nhau, tôi điều chỉnh các chức năng để xem xét như thế này và thì đấy nó hoạt động:public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
Jonny

38

Vấn đề với tất cả các cách tiếp cận này, bao gồm cả của tôi, là chúng không loại bỏ được chi phí đánh giá các printlập luận. Bất kể bạn sử dụng cái nào trong số chúng, điều này sẽ tốn kém:

print(myExpensiveFunction())

Giải pháp tốt duy nhất là gói lệnh in thực tế trong biên dịch có điều kiện (giả sử rằng điều đó DEBUGchỉ được xác định cho các bản dựng gỡ lỗi):

#if DEBUG
print(myExpensiveFunction())
#endif

Điều đó, và chỉ điều đó, ngăn không cho myExpensiveFunctionđược gọi trong một bản phát hành.

Tuy nhiên, bạn có thể đẩy lùi đánh giá một cấp độ bằng cách sử dụng tính năng tự động đóng cửa . Do đó, bạn có thể viết lại giải pháp của tôi (đây là Swift 3) như thế này:

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

Điều này giải quyết vấn đề chỉ trong trường hợp bạn chỉ in một thứ, điều này thường đúng. Đó là vì item()không được gọi trong chế độ phát hành. print(myExpensiveFunction())do đó không còn tốn kém nữa, bởi vì cuộc gọi được bao bọc trong một lệnh đóng mà không được đánh giá, và trong chế độ phát hành, nó sẽ không được đánh giá chút nào.


Việc sử dụng là @autoclosuregì?
kelin

@matt trong cuốn sách của bạn, bạn đề cập đến "Một tính năng quan trọng của bản in là nó bị ngăn chặn hiệu quả khi ứng dụng được khởi chạy độc lập với Xcode", điều đó có nghĩa là chúng ta có thể để lại các bản in của mình trong các ứng dụng đã gửi của chúng tôi những ngày này, hay tôi đang hiểu nhầm cái gì đó?
tên người dùng ẩn

@ hidden-username Có, tôi có xu hướng để lại bảng sao kê của mình printtrong mã vận chuyển, nhưng điều đó khác với câu trả lời của tôi ở đây. Một printđầu ra câu lệnh không được gửi tới bảng điều khiển trong bản phát hành độc lập với Xcode của bạn, nhưng nó vẫn được đánh giá , vì vậy, bạn vẫn nên biết cách ngăn đánh giá đó trong trường hợp tốn kém hoặc có tác dụng phụ không mong muốn.
matt

@matt oh ok ... Yeah, tôi đã hiểu lầm nó. Tôi sẽ bình luận chúng ra. Cảm ơn
tên người dùng bị ẩn

Cách tiếp cận này sẽ xóa chuỗi đã in khỏi tệp nhị phân? Ví dụ: nếu tôi sử dụng phương pháp đó và một nơi nào đó trong ứng dụng của tôi, tôi đặt "print (" người dùng đã đăng nhập ")" và sau đó nếu ai đó cố gắng thiết kế ngược lại ứng dụng của tôi thì họ sẽ tìm thấy chuỗi này ở đâu đó hay nó sẽ không ở đó?
Leszek Szary

18

Như đã lưu ý, tôi là một sinh viên và cần những thứ được xác định rõ ràng hơn một chút để làm theo. Sau rất nhiều nghiên cứu, trình tự tôi cần làm theo là:

Bấm vào tên dự án ở đầu Bộ điều hướng Tệp ở bên trái cửa sổ dự án Xcode. Đây là dòng có tên của dự án, có bao nhiêu mục tiêu xây dựng và phiên bản iOS SDK.

Chọn tab Cài đặt bản dựng và cuộn xuống phần " Trình biên dịch Swift - Cờ tùy chỉnh " ở gần cuối. Nhấp vào Mũi tên Xuống bên cạnh Cờ khác để mở rộng phần này.

Nhấp vào dòng Debug để chọn nó. Đặt con trỏ chuột lên phía bên phải của dòng và nhấp đúp. Chế độ xem danh sách sẽ xuất hiện. Nhấp vào nút + ở phía dưới bên trái của chế độ xem danh sách để thêm giá trị. Một trường văn bản sẽ trở nên hoạt động.

Trong trường văn bản, nhập văn bản -D DEBUGvà nhấn Quay lại để xác nhận dòng.

Thêm một tệp Swift mới vào dự án của bạn. Bạn sẽ muốn tạo một lớp tùy chỉnh cho tệp, vì vậy hãy nhập văn bản dọc theo các dòng sau:

class Log {

  var intFor : Int

  init() {
    intFor = 42
   }

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

Tôi đã gặp sự cố để lớp được Xcode chấp nhận hôm nay, vì vậy init có thể nặng hơn một chút so với mức cần thiết.

Bây giờ, bạn sẽ cần tham chiếu đến lớp tùy chỉnh của mình trong bất kỳ lớp nào mà bạn định sử dụng hàm tùy chỉnh mới thay cho println()Thêm cái này làm thuộc tính trong mọi lớp hiện hành:

   let logFor = Log()

Bây giờ bạn có thể thay thế bất kỳ trường hợp nào của println()với logFor.DLog(). Đầu ra cũng bao gồm tên của hàm trong đó dòng được gọi.

Lưu ý rằng bên trong các hàm lớp, tôi không thể gọi hàm trừ khi tôi tạo một bản sao của hàm dưới dạng hàm lớp trong lớp đó và println()cũng linh hoạt hơn một chút với đầu vào, vì vậy tôi không thể sử dụng hàm này trong mọi trường hợp trong mã của tôi.


8
Không cần tạo lớp tùy chỉnh cho nhật ký gỡ lỗi. Sẽ dễ dàng và thiết thực hơn khi sử dụng một hàm toàn cục.
Vojtech Vrbka

Việc sử dụng intFor = 42 là gì?
Ted

15

Swift 5

Chỉ cần tạo một tệp mới trong dự án của bạn và dán mã này vào:

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

Chữ ký hàm này khớp với chữ ký mặc định của Swift để nó "ghi đè" hàm trong dự án của bạn. Nếu cần, bạn vẫn có thể truy cập bản gốc bằng cách sử dụng Swift.print().

Khi bạn đã thêm mã ở trên, hãy tiếp tục sử dụng print()mã như bình thường và nó sẽ chỉ in trong các bản dựng gỡ lỗi.

Lưu ý: Việc thực hiện forEachin từng mục sẽ loại bỏ các dấu ngoặc mảng gây phiền nhiễu xung quanh các câu lệnh in hiển thị nếu bạn chỉ cần chuyển itemsthẳng vào Swift.print().

Đối với bất kỳ ai tương đối mới làm quen với Swift, bạn có thể tự hỏi cái quái gì vậy $0. Nó chỉ đại diện cho đối số đầu tiên được truyền vào forEachkhối. Câu forEachlệnh cũng có thể được viết như thế này:

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

Cuối cùng nếu bạn quan tâm, khai báo Swift printtrông như thế này:

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

Câu trả lời của tôi ở trên phản ánh việc triển khai Swift chính xác - mặc dù tôi không bao giờ in nhiều hơn một thứ hoặc thay đổi dấu phân tách / dấu chấm dứt. Nhưng ai biết được, bạn có thể muốn.


2
khai báo hàm này ở đâu, đây là phần mở rộng hay smth như thế này? Tôi chỉ không muốn khai báo nó trong mỗi tệp)
Matrosov Alexander

1
@MatrosovAlexander Bạn chỉ có thể tạo một tệp nhanh ở bất kỳ đâu trong dự án ứng dụng của mình và đưa mã này vào. Trình biên dịch đủ thông minh để giúp nó có thể truy cập toàn cầu.
Trev 14

11

Đây là một hàm mà tôi sử dụng, nó hoạt động hoàn hảo trong 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
    }

Đây là một ví dụ về kết quả mà nó tạo ra:

ảnh chụp màn hình đầu ra

Giải trình:

  • dấu kiểm màu xanh lục được sử dụng để cho phép bạn xem nhanh tin nhắn in (gLog) của mình trong bảng điều khiển, nơi đôi khi chúng có thể bị lạc trong một biển tin nhắn khác

  • dấu thời gian / ngày tháng

  • luồng mà nó đang được chạy - trong trường hợp của tôi, đó là MainThread (mà tôi gọi là UI), hoặc không phải MainThread (mà tôi gọi là BG, cho luồng nền)

  • tên của tệp mà thông báo gLog nằm trong đó

  • hàm trong tệp mà thông báo gLog nằm trong đó

  • số dòng của tin nhắn gLog

  • thông báo gLog thực tế mà bạn muốn in ra

Hy vọng điều này hữu ích cho người khác!


cái này có thể được đưa vào một tệp riêng biệt để sử dụng trên toàn ứng dụng không? Tôi đã thử đặt nó trong một tệp lớp riêng biệt, như một phương thức lớp. Nhưng nó gặp sự cố với libMobileGestalt MobileGestaltSupport.m: 153: pid 2574 (Demo) không có quyền truy cập hộp cát cho frZQaeyWLUvLjeuEK43hmg và KHÔNG có quyền thích hợp libMobileGestalt MobileGestalt.c: 550: không có quyền truy cập vào InverseDevicearID: // sự cố ) Thông báo từ trình gỡ lỗi: Đã chấm dứt do sự cố bộ nhớ
omarojo

omarojo, tôi sử dụng nó như một hàm toàn cầu trong ứng dụng của mình. Không cần lớp học. Tôi có một tệp tên utils.swift, chứa tất cả các chức năng tiện ích của tôi, chẳng hạn như cái này. Bạn chỉ cần đảm bảo nhập Foundation - có lẽ đó là bước bạn đã bỏ qua? Bằng cách này, để biết thêm về tuyên bố chức năng của bạn trong vòng lớp học, như các chức năng tĩnh trong lớp học, hay như các chức năng toàn cầu, hãy xem Câu hỏi SO và câu trả lời: stackoverflow.com/questions/30197548/...
Gene Loparco

Vâng, nó hoạt động chỉ bằng cách tạo một tệp mới với chức năng bên trong. Vì một số lý do có nó như một Hàm lớp sẽ làm ứng dụng bị lỗi mà không có thông báo gỡ lỗi rõ ràng.
omarojo

Cảm ơn người đàn ông này, thật xấu hổ tôi đã không phát hiện ra nó trước đây. Đã tiết kiệm cho tôi rất nhiều gỡ lỗi đau đầu.
beowulf

Niềm vui của tôi @beowulf!
Gene Loparco

9

Đã thử nghiệm với Swift 2.1 & Xcode 7.1.1

Có một cách dễ dàng để loại trừ tất cả các câu lệnh in khỏi các phiên bản phát hành, khi bạn biết rằng các hàm trống sẽ bị trình biên dịch Swift loại bỏ .

Lưu ý: Trong kỷ nguyên của Objective-C, có một trình phân tích cú pháp trước có thể được sử dụng để loại bỏ các câu lệnh NSLog trước khi trình biên dịch bắt đầu, như được mô tả trong câu trả lời của tôi ở đây . Nhưng vì Swift không còn trình phân tích cú pháp trước nên cách tiếp cận này không còn hợp lệ nữa.

Đây là những gì tôi sử dụng ngày hôm nay như một chức năng nhật ký nâng cao và có thể cấu hình dễ dàng, mà không bao giờ phải lo lắng về việc xóa nó trong các bản phát hành. Ngoài ra, bằng cách đặt các cờ trình biên dịch khác nhau, bạn có thể chỉnh sửa thông tin được ghi khi cần thiết.

Bạn có thể tinh chỉnh chức năng khi cần thiết, mọi đề xuất để cải thiện nó đều được hoan nghênh!

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

Đây là nơi bạn đặt cờ trình biên dịch:

nhập mô tả hình ảnh ở đây

Một ví dụ đầu ra với tất cả các cờ trên trông như thế này:

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

Mã có log () trông giống như sau:

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

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

Đẹp quá! Tôi đã lấy nó từ đây và cuối cùng đã tạo ra AELogAEConsole .
tadija

Điều này đang hoạt động tốt ở chế độ GỠ LỖI. Bây giờ, tôi đã thay đổi sang chế độ RELEASE từ Edit Scheme. Nó cũng hiển thị cửa sổ bảng điều khiển đăng nhập cho chế độ Phát hành. Tại sao vậy?
Jayprakash Dubey

Đối với Swift 3.2 trong Xcode 9, tôi cần thay đổi NSLog để in và gọi bằng nhật ký (thông báo: "xin chào"), ngoài ra tôi phải đặt các cờ là "-D" "kLOG_ENABLE", với dấu ngoặc kép. Tất cả các bản cập nhật phiên bản nhanh chóng khác đã được trình biên dịch thu thập với các bản sửa lỗi được đề xuất.
iCyberPaul

1
Ở đây bạn nói rằng "các chức năng trống đã bị xóa bởi trình biên dịch Swift", chúng ta tìm thấy điều đó ở đâu trong tài liệu? Làm thế nào để bạn biết đó là trường hợp? @ ronny-webers
zumzum

7

Đơn giản hơn nữa, sau khi đảm bảo -D DEBUGđược đặt cho OTHER_SWIFT_FLAGScài đặt bản dựng Gỡ lỗi:

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

Tôi nghi ngờ điều này có thể yêu cầu "ở đâu" vì các đối tượng có thể in tuân theo một trong những giao thức hệ thống mà bạn thấy hiếm khi được đề cập trong vids cho wwdc và tôi nghĩ rằng ở cuối (các) hướng dẫn nhanh 1.2 so với 2, đã quên sự khác biệt nếu có là một với một hệ thống
Stephen J

Cho đến nay, nó hoạt động với Swift 1.2. Chưa thử 2.0.
Rivera

6

XCode 8 đã giới thiệu một số cài đặt bản dựng mới .
Cụ thể, một cái được đề cập Active Compilation Conditionsthực hiện theo cách tương tự như những gì cài đặt Cờ khác đã làm.

"Điều kiện biên dịch hoạt động" là một cài đặt xây dựng mới để chuyển cờ biên dịch có điều kiện đến trình biên dịch Swift.

Theo XCode 8 (được thử nghiệm trong 8.3.2), bạn sẽ nhận được điều này theo mặc định:

nhập mô tả hình ảnh ở đây

Vì vậy, không có bất kỳ cấu hình nào, bạn có thể viết như sau:

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

Tôi thực sự khuyên bạn rằng nếu bạn sử dụng cách tiếp cận này một cách rộng rãi, hãy tạo một lớp / struct / function bao bọc logic ghi nhật ký này. Bạn có thể muốn mở rộng điều này hơn nữa trên đường.


4

Varun Naharia có giải pháp tốt hơn cho đến nay. Tôi sẽ kết hợp câu trả lời của anh ấy với câu trả lời của Rivera ...

  1. tạo -D DEBUGcờ trên các chỉ thị của trình biên dịch, xây dựng cài đặt.
  2. sau đó thêm mã này:

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

Mã này sẽ chuyển đổi mọi thứ printthành không có gì để phát hành.


3

Swift 4 Xcode 10.0

có lẽ bạn có thể sử dụng cái này

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

Lý do của việc sử dụng @autoclosurelà nếu bạn truyền một hàm làm tham số thông báo, hàm sẽ chỉ được gọi trong chế độ gỡ lỗi, nó sẽ gây ra lỗi hiệu suất.

không giống như Swift.print(_ items: Any..., separator: String = default, terminator: String = default)hàm, giải pháp của tôi chỉ có một tham số, vì trong hầu hết các trường hợp, chúng ta không truyền nhiều tham số vì hàm print chỉ hiển thị thông tin trong bảng điều khiển, chúng ta chỉ có thể chuyển đổi các tham số thành Chuỗi : "\(param1)"+"\(param2)", đúng không? hy vọng bạn thích giải pháp của tôi


1

Bạn cũng có thể sử dụng một điểm ngắt, đặt nó tiếp tục sau khi đánh giá và viết thông báo in vào điểm ngắt!

nhập mô tả hình ảnh ở đây


0

Bạn có thể xác định debug_printlnnội dung của ai sẽ là:

#if DEBUG
  println()
#endif

Cảm ơn, tôi có thể xác định nó tốt nhất ở đâu? Tôi là một sinh viên, tôi sợ và tôi đánh giá rất cao sự giúp đỡ nhưng yêu cầu bối cảnh rõ ràng hơn.
Nate Birkholz

Bạn sẽ khai báo nó trong một tệp tiêu đề mà bạn sẽ nhập vào bất kỳ nơi nào bạn muốn sử dụng nó.
Ian MacDonald

0

Giải pháp của tôi là sử dụng mã này trong AppDelegate trước lớp

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

}

0

cho giải pháp của tôi, tôi làm cho nó đơn giản

import UIKit

class DLog: NSObject {

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

   }

}

sau đó để hiển thị nó chỉ cần gọi

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

0

Tôi đã kết thúc bằng cách sử dụng cái này:

#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

Nó khá nhỏ gọn, in một số thông tin hữu ích (dấu thời gian, tên tệp nhanh, dòng mã, tên hàm) và ít nhất trong các thử nghiệm của tôi, tôi không thể tìm thấy bất kỳ chuỗi đã ghi nào trong tệp nhị phân ứng dụng khi mở bằng hex editior.


0

Đơn giản hơn nữa: tận dụng lợi thế của thực tế là các xác nhận được xóa khỏi các bản dựng phát hành và chỉ từ đó gọi bản in. Điều này loại bỏ tất cả các lệnh gọi nhật ký (có, ngay cả các lệnh gọi đến Log.da) vì chúng trống khi xây dựng để phát hành.

Nhưng tôi cũng nghe nói rằng bản in được gỡ bỏ cho các bản dựng phát hành, nhưng không thể tìm thấy nó bằng văn bản. Vì vậy, hiện tại, tôi đang sử dụng một cái gì đó như thế này Logbên dưới. Tôi có một phiên bản hấp dẫn hơn trên GitHub với biểu tượng cảm xúc (để dễ đọc) và các chủ đề nhật ký (để nhất quán):

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

Trong mã:

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

Thấy trong các khu vực debug Xcode chỉ khi chạy một debug xây dựng:

13: 36: 15.047 - Điều này chỉ được xử lý trong bản dựng gỡ lỗi.


0

Dự án của tôi được phát triển trong Objective C, nhưng từ năm ngoái, tôi đã bắt đầu hợp nhất mã mới trong Swift, Vì vậy, trong Swift giải pháp dưới đây phù hợp với tôi, tôi đã thêm mã đó vào tệp hằng Swift của tôi:

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

0

Điều này hoạt động đối với tôi (thêm điều này làm chức năng toàn cục trong dự án)

func print(_ items: Any...) {
    #if DEBUG
        Swift.print(items[0])
    #endif
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.