什么是Swift相当于 – [NSObject描述]?

What is the Swift equivalent of -[NSObject description]?

在objective-c中,可以在类中添加description方法,以帮助调试:

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

然后在调试器中,可以执行以下操作:

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

Swift中的等价物是什么?Swift的repl输出有助于:

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

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

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

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

1
2
3
4
5
6
/// 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
2
3
4
5
6
7
8
9
10
11
  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)

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

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

有更好的方法吗?


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

例如:

1
2
3
4
5
6
7
8
9
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中使用CustomStringConvertibleCustomDebugStringConvertible协议的示例:

页面内容查看控制器.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import UIKit

class PageContentViewController: UIViewController {

    var pageIndex : Int = 0

    override var description : String {
        return"**** PageContentViewController
pageIndex equals \(pageIndex) ****
"
    }

    override var debugDescription : String {
        return"---- PageContentViewController
pageIndex equals \(pageIndex) ----
"
    }

            ...
}

视图控制器.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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)
    }

          ...
}

打印出:

1
2
3
4
5
6
7
8
**** PageContentViewController
pageIndex equals 0 ****

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

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

注意:如果您有一个自定义类,它不包含在UIKIT或基础库中包含的任何类中,则使其继承EDCOX1×5类,或者使其符合EDCOX1、0和EDCOX1 4个协议。


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

在xcode 7.0测试版中工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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))"
}

关于CustomStringConvertible的答案是可行的。就个人而言,为了尽可能保持类(或结构)定义的整洁,我还将把描述代码分为单独的扩展名:

1
2
3
4
5
6
7
8
9
10
11
12
13
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!"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
    }
}