【问题标题】:What is the Swift equivalent of -[NSObject description]?-[NSObject 描述] 的 Swift 等价物是什么?
【发布时间】:2014-07-29 07:20:41
【问题描述】:

在 Objective-C 中,可以将description 方法添加到他们的类中以帮助调试:

@implementation MyClass
- (NSString *)description
{
    return [NSString stringWithFormat:@"<%@: %p, foo = %@>", [self class], foo _foo];
}
@end

然后在调试器中,你可以这样做:

po fooClass
<MyClass: 0x12938004, foo = "bar">

Swift 中的等价物是什么? Swift 的 REPL 输出可能会有所帮助:

  1> class MyClass { let foo = 42 }
  2> 
  3> let x = MyClass()
x: MyClass = {
  foo = 42
}

但我想覆盖此行为以打印到控制台:

  4> println("x = \(x)")
x = C11lldb_expr_07MyClass (has 1 child)

有没有办法清理这个println 输出?我见过Printable 协议:

/// This protocol should be adopted by types that wish to customize their
/// textual representation.  This textual representation is used when objects
/// are written to an `OutputStream`.
protocol Printable {
    var description: String { get }
}

我认为println 会自动“看到”这种情况,但事实并非如此:

  1> class MyClass: Printable {
  2.     let foo = 42
  3.     var description: String { get { return "MyClass, foo = \(foo)" } }
  4. }   
  5> 
  6> let x = MyClass()
x: MyClass = {
  foo = 42
}
  7> println("x = \(x)")
x = C11lldb_expr_07MyClass (has 1 child)

相反,我必须明确调用描述:

 8> println("x = \(x.description)")
x = MyClass, foo = 42

有没有更好的办法?

【问题讨论】:

    标签: swift


    【解决方案1】:

    here 所述,您还可以使用 Swift 的反射功能,通过使用此扩展来让您的类生成自己的描述:

    extension CustomStringConvertible {
        var description : String {
            var description: String = "\(type(of: self)){ "
            let selfMirror = Mirror(reflecting: self)
            for child in selfMirror.children {
                if let propertyName = child.label {
                    description += "\(propertyName): \(child.value), "
                }
            }
            description = String(description.dropLast(2))
            description += " }"
            return description
        }
    }
    

    【讨论】:

      【解决方案2】:

      要在 Swift 类型上实现这一点,您必须实现 CustomStringConvertible 协议,然后还要实现一个名为 description 的字符串属性。

      例如:

      class MyClass: CustomStringConvertible {
          let foo = 42
      
          var description: String {
              return "<\(type(of: self)): foo = \(foo)>"
          }
      }
      
      print(MyClass()) // prints: <MyClass: foo = 42>
      

      注意:type(of: self) 获取当前实例的类型,而不是显式写入“MyClass”。

      【讨论】:

      • 很棒的发现!我要提交一个雷达文件——“swift -i sample.swift”和“swift sample.swift && sample”的 println 输出不同。
      • 感谢您提供相关信息。我在操场上试用 Printable,但它现在确实不起作用。很好,听说它可以在应用程序中使用。
      • Printable 在操场上确实可以工作,但如果该类来自 NSObject
      • 在 Swift 2.0 中它已更改为 CustomStringConvertible 和 CustomDebugStringConvertible
      • 另外,使用 Xcode 7.2 在 Playground 中使用 CustomStringConvertible 和 CustomDebugStringConvertible 没有问题
      【解决方案3】:
      class SomeBaseClass: CustomStringConvertible {
      
          //private var string: String = "SomeBaseClass"
      
          var description: String {
              return "\(self.dynamicType)"
          }
      
          // Use this in newer versions of Xcode
          var description: String {
              return "\(type(of: self))"
          }
      
      }
      
      class SomeSubClass: SomeBaseClass {
          // If needed one can override description here
      
      }
      
      
      var mySomeBaseClass = SomeBaseClass()
      // Outputs SomeBaseClass
      var mySomeSubClass = SomeSubClass()
      // Outputs SomeSubClass
      var myOtherBaseClass = SomeSubClass()
      // Outputs SomeSubClass
      

      【讨论】:

        【解决方案4】:

        只需使用CustomStringConvertiblevar description: String { return "Some string" }

        适用于 Xcode 7.0 beta

        class MyClass: CustomStringConvertible {
          var string: String?
        
        
          var description: String {
             //return "MyClass \(string)"
             return "\(self.dynamicType)"
          }
        }
        
        var myClass = MyClass()  // this line outputs MyClass nil
        
        // and of course 
        print("\(myClass)")
        
        // Use this newer versions of Xcode
        var description: String {
            //return "MyClass \(string)"
            return "\(type(of: self))"
        }
        

        【讨论】:

          【解决方案5】:

          CustomStringConvertible 相关的答案是必经之路。就个人而言,为了使类(或结构)定义尽可能干净,我还将描述代码分离到一个单独的扩展中:

          class foo {
              // Just the basic foo class stuff.
              var bar = "Humbug!"
          }
          
          extension foo: CustomStringConvertible {
              var description: String {
                  return bar
              }
          }
          
          let xmas = foo()
          print(xmas)  // Prints "Humbug!"
          

          【讨论】:

            【解决方案6】:
            struct WorldPeace: CustomStringConvertible {
                let yearStart: Int
                let yearStop: Int
            
                var description: String {
                    return "\(yearStart)-\(yearStop)"
                }
            }
            
            let wp = WorldPeace(yearStart: 2020, yearStop: 2040)
            print("world peace: \(wp)")
            
            // outputs:
            // world peace: 2020-2040
            

            【讨论】:

              【解决方案7】:

              在 Swift 中使用 CustomStringConvertibleCustomDebugStringConvertible 协议的示例:

              PageContentViewController.swift

              import UIKit
              
              class PageContentViewController: UIViewController {
              
                  var pageIndex : Int = 0
              
                  override var description : String { 
                      return "**** PageContentViewController\npageIndex equals \(pageIndex) ****\n" 
                  }
              
                  override var debugDescription : String { 
                      return "---- PageContentViewController\npageIndex equals \(pageIndex) ----\n" 
                  }
              
                          ...
              }
              

              ViewController.swift

              import UIKit
              
              class ViewController: UIViewController
              {
              
                  /*
                      Called after the controller's view is loaded into memory.
                  */
                  override func viewDidLoad() {
                      super.viewDidLoad()
              
                      let myPageContentViewController = self.storyboard!.instantiateViewControllerWithIdentifier("A") as! PageContentViewController
                      print(myPageContentViewController)       
                      print(myPageContentViewController.description)
                      print(myPageContentViewController.debugDescription)
                  }
              
                        ...
              }
              

              打印出来的内容:

              **** PageContentViewController
              pageIndex equals 0 ****
              
              **** PageContentViewController
              pageIndex equals 0 ****
              
              ---- PageContentViewController
              pageIndex equals 0 ----
              

              注意:如果您有一个不继承自 UIKitFoundation 库中包含的任何类的自定义类,则使其继承NSObject 类或使其符合 CustomStringConvertibleCustomDebugStringConvertible 协议。

              【讨论】:

              • 函数必须声明为public
              猜你喜欢
              • 1970-01-01
              • 2010-09-24
              • 1970-01-01
              • 2014-08-12
              • 2014-08-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多