【问题标题】:How to print() to Xcode console in SwiftUI?如何在 SwiftUI 中将 print() 打印到 Xcode 控制台?
【发布时间】:2019-10-24 08:20:54
【问题描述】:

所以我尝试在 SwiftUI 视图中调试时放置一个打印语句。

print("landmark: \(landmark)")

在下面的正文中。

var body: some View {
    NavigationView {
        List {
            Toggle(isOn: $userData.showFavoritesOnly) {
                Text("Favorite only")
            }
            ForEach(landmarkData) { landmark in
                print("landmark: \(landmark)")
                if !self.userData.showFavoritesOnly || landmark.isFavorite {
                    NavigationButton(destination: LandmarkDetail(landmark: landmark)) {
                        LandmarkRow(landmark: landmark)
                    }
                }
            }
        }
       .navigationBarTitle(Text("Landmarks"))            
    }
}

编译器错误输出:

那么,在 SwiftUI 中打印到控制台的正确方法是什么?

编辑: 我让 Landmark 符合 CustomStringConvertible

struct Landmark: Hashable, Codable, Identifiable, CustomStringConvertible {

var description: String { name+"\(id)" }

var id: Int
var name: String
.....

我仍然收到“字符串不可转换为任何”错误。它现在应该工作吗?

【问题讨论】:

  • 您的地标是否符合CustomStringConvertible
  • 您的问题是关于打印的,但由于出现错误,您无法编译。先修复错误,我确信打印会正常工作。
  • 我编辑了这个问题。出于某种原因,我不得不重新清理和构建,然后在离开时出现另一个错误。
  • 您是否尝试在 NavigationButton 之前添加return
  • 在 Xcode 12.4 上,只有当我使用真实设备时,所有打印结果才会出现在调试区域中。

标签: swiftui


【解决方案1】:

View 上的以下扩展与 print 一样直观,因为它复制了默认的 print(_:separator:terminator:) 函数签名和行为。

extension View {
    func printUI(_ args: Any..., separator: String = " ", terminator: String = "\n") -> EmptyView {
        let output = args.map(String.init(describing:)).joined(separator: separator)
        print(output, terminator: terminator)
        return EmptyView()
    }
}

使用示例:

struct ContentView: View {
    var body: some View {
        VStack {
            printUI("ContentView", "1")
            printUI("ContentView", "2", separator: ", ", terminator: "\n.\n.\n")
            printUI("ContentView", "3", separator: "; ")

            Text("Hello, World!")
        }
    }
}
控制台输出:

内容视图 1
内容视图,2
.
.
内容视图; 3

【讨论】:

    【解决方案2】:

    // 试试这个,在视图上添加一个'return',然后'print'可以保持活跃。

    struct ContentView: View {
        var num: Int = 1
        
        var body: some View {
            print(num)
            
            return  Text("hello")
        
        }
    }
    

    【讨论】:

      【解决方案3】:

      给你。它就像简单的打印一样工作,但在视图中。

            func printv( _ data : Any)-> EmptyView{
             print(data)
             return EmptyView()
            }
      

      然后像这样使用它

      struct ContentView: View {
      var body: some View  {
          VStack() {
              
              Text("hello To SwiftUI")
              
              printv("its easy to code in SwiftUI")
              
              Text("And Good to have you here")
          }
        } 
      }
      

      【讨论】:

        【解决方案4】:

        调试预览的非常简单的方法:

        1. 在 Xcode 11 中打开您的 Swift 项目。
        2. 右键单击(或按住 Control 单击)预览右下角的实时预览按钮。
        3. 选择调试预览。

        How to debug your SwiftUI previews in Xcode

        【讨论】:

          【解决方案5】:

          可以概括为:

          extension View {
              func Perform(_ block: () -> Void) -> some View {
                  block()
                  return EmptyView()
              }
          }
          

          所以在你的例子中:

          ForEach(landmarkData) { landmark in
              Perform { print("landmark: \(landmark)") }
              if !self.userData.showFavoritesOnly || landmark.isFavorite {
                  NavigationButton(destination: LandmarkDetail(landmark: landmark)) {
                      LandmarkRow(landmark: landmark)
                  }
              }
          }
          

          【讨论】:

            【解决方案6】:

            至少在 Xcode 12/Swift 5.3 中,您可以轻松地在函数构建器的任何位置添加打印语句,只需将其返回值存储在通配符中,有效地忽略它:

            let _ = print("hi!")
            

            无需设置或其他详细信息!

            【讨论】:

            • 天啊,为什么 SwiftUI 中的某些事情必须如此奇怪,很多事情都感觉像是“变通办法”或“黑客”,只是为了达到一个简单的结果。
            【解决方案7】:

            您可以在主体结构中打印,但要这样做,您必须显式返回要渲染的视图。通常在 SwiftUI 中,body 属性会隐式返回视图。例如,这将在您尝试打印时抛出错误:

            struct SomeView: View {
              @State var isOpen = false
            
              var body: some View {
                print(isOpen) // error thrown here
            
                VStack {
                  // other view code
                |
              }
            }
            

            但是如果我们明确地返回我们想要的视图,那么它将起作用,例如

            struct SomeView: View {
              @State var isOpen = false
            
              var body: some View {
                print(isOpen) // this ok because we explicitly returned the view below
            
                 // Notice the added 'return' below
                 return VStack {
                  // other view code
                }
              }
            }
            

            如果您希望在返回视图之前查看状态或环境对象的变化情况,上述方法将很有效,但如果您想在尝试返回的视图中打印更深的内容,那么我会选择@Rok Krulec 回答。

            【讨论】:

              【解决方案8】:

              这是一个助手 Print( ... ) 视图,其作用类似于 print( ... ) 函数,但在视图中

              把它放在你的任何视图文件中

              extension View {
                  func Print(_ vars: Any...) -> some View {
                      for v in vars { print(v) }
                      return EmptyView()
                  }
              }
              

              并像这样在body 内部使用

              Print("Here I am", varOne, varTwo ...)
              

              或者像这样在ForEach {}里面

              self.Print("Inside ForEach", varOne, varTwo ...)
              

              注意:与现有视图组合时,您可能需要将Print() 放入Group {}

              【讨论】:

              • 这个修改让你可以使用“打印”语法:func Print(_ items: Any..., separator: String = " ", terminator: String = "\n") -> some View { let string = items.map{String(describing: $0)}.joined(separator: separator) print("Print:", string, terminator: terminator) // 可以在这里添加其他东西 return EmptyView() } self.Print( "view named", self.someName, "number:", self.num)
              • 任何想要时间戳的人的 NSLog 版本:extension View { func NSLogView(_ format: String, _ args: CVarArg...) -> some View { NSLog(format, args) return EmptyView() } }
              【解决方案9】:

              可以使用 print() 记住所有 SwiftUI 视图内容都是 (a) 隐式闭包和 (b) 强烈建议尽可能分解视图以具有简单的结构,因此它可能如下所示...

              struct Model: Identifiable {
                  let value: String
                  var id: String {
                      value
                  }
                  init (_ value: String) {
                      self.value = value
                  }
              }
              
              struct TestView: View {
                  @State var showFavoritesOnly = false
                  @State var listData: [Model] = [Model("one"), Model("two"), Model("three")]
              
                  var body: some View {
                      NavigationView {
                          List {
                              Toggle(isOn: $showFavoritesOnly) {
                                  Text("Favorite only")
                              }
                              ForEach(listData) { data in
                                  self.rowView(data: data)
                              }
                          }
                      }
                  }
              
                  private func rowView(data: Model) -> some View {
              #if DEBUG
                      print(">> \(data.value)")
              #endif
                      return NavigationLink(destination: Text("Details")) {
                          Text("Go next from \(data.value)")
                      }
                  }
              }
              

              ...并在预览中右键单击以选择作为调试预览运行我们得到:

              2019-10-31 14:28:03.467635+0200 Test[65344:11155167] [Agent] Received connection, creating agent
              2019-10-31 14:28:04.472314+0200 Test[65344:11155168] [Agent] Received display message
              >> one
              >> two
              >> three
              

              【讨论】:

                【解决方案10】:

                尝试右键单击实时预览播放按钮并从弹出窗口中选择“调试预览”

                【讨论】:

                • 关于 macOS 中 SwiftUI 的调试预览,最新的 Xcode (11.3) 似乎还不支持使用print() 将日志打印到 Xcode 的控制台。 AFAIK 目前只有带有日志消息操作的断点可以做到这一点。或者,作为另一种解决方法,您可以将调试预览与 Console.app 一起使用,以便您可以在应用程序中查看调试日志。请注意,您需要使用NSLog(),因为print() 不适用于输出到 Console.app。
                • 在 Xcode 12.3 中,将日志打印到 Xcode 的控制台似乎仍然无法正常工作:(
                【解决方案11】:

                您不能在正文结构中打印,即 some view 类型的结构。对于打印,您需要从正文结构中创建功能并使用按钮或其他方式调用它。

                【讨论】:

                  【解决方案12】:

                  你不能因为你在一个计算属性中。例如,您需要一个按钮,并在您定义打印的操作中。或者使用断点

                  【讨论】:

                    猜你喜欢
                    • 2018-12-12
                    • 2014-04-14
                    • 2013-01-21
                    • 2021-02-17
                    • 1970-01-01
                    • 2014-10-10
                    • 1970-01-01
                    • 2012-03-04
                    • 2014-08-28
                    相关资源
                    最近更新 更多