Tương đương Swift của - [mô tả NSObject] là gì?


163

Trong Objective-C, người ta có thể thêm một descriptionphương thức vào lớp của chúng để hỗ trợ gỡ lỗi:

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

Sau đó, trong trình gỡ lỗi, bạn có thể làm:

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

Tương đương trong Swift là gì? Đầu ra REPL của Swift có thể hữu ích:

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

Nhưng tôi muốn ghi đè hành vi này để in lên bàn điều khiển:

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

Có cách nào để làm sạch printlnđầu ra này ? Tôi đã thấy Printablegiao thức:

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

Tôi hình dung điều này sẽ tự động được "nhìn thấy" printlnnhưng dường như không phải vậy:

  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)

Và thay vào đó tôi phải gọi mô tả rõ ràng:

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

Có cách nào tốt hơn?

Câu trả lời:


124

Để thực hiện điều này trên một loại Swift, bạn phải thực hiện CustomStringConvertiblegiao thức và sau đó cũng thực hiện một thuộc tính chuỗi được gọi description.

Ví dụ:

class MyClass: CustomStringConvertible {
    let foo = 42

    var description: String {
        return "<\(type(of: self)): foo = \(foo)>"
    }
}

print(MyClass()) // prints: <MyClass: foo = 42>

Lưu ý: type(of: self)lấy loại phiên bản hiện tại thay vì viết rõ ràng 'MyClass'.


3
Tuyệt vời tìm thấy! Tôi sẽ gửi một radar - đầu ra println của "swift -i sample.swift" và "swift sample.swift && sample" khác nhau.
Jason

Cảm ơn thông tin về điều đó. Tôi đã thử dùng Printable trong một sân chơi và thực sự nó không hoạt động ngay bây giờ. Thật tốt khi nghe nó hoạt động trong một ứng dụng.
Tod Cickyham

Printable không hoạt động trong sân chơi, nhưng nếu lớp học xuống từ NSObject
dar512

5
Trong Swift 2.0, nó đã thay đổi thành CustomStringConvertible và CustomDebugStringConvertible
Mike Vosseller

Ngoài ra, không có vấn đề gì khi sử dụng CustomStringConvertible và CustomDebugStringConvertible trong Sân chơi với Xcode 7.2
Nicholas Credli

54

Ví dụ về việc sử dụng CustomStringConvertiblevà các CustomDebugStringConvertiblegiao thức trong Swift:

PageContentViewControll.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" 
    }

            ...
}

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

          ...
}

Mà in ra:

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

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

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

Lưu ý: nếu bạn có một lớp tùy chỉnh không kế thừa từ bất kỳ lớp nào có trong các thư viện UIKit hoặc Foundation , thì hãy làm cho nó kế thừa NSObjectlớp hoặc làm cho nó tuân thủ CustomStringConvertiblevà các CustomDebugStringConvertiblegiao thức.


chức năng phải được khai báo là công khai
Karsten

35

Chỉ cần sử dụng CustomStringConvertiblevar description: String { return "Some string" }

hoạt động trong 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))"
}

20

Các câu trả lời liên quan đến CustomStringConvertiblelà cách để đi. Cá nhân, để giữ cho định nghĩa lớp (hoặc struct) càng sạch càng tốt, tôi cũng sẽ tách mã mô tả thành một phần mở rộng riêng:

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!"

8
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

6

Như được mô tả ở đây , bạn cũng có thể sử dụng các khả năng phản chiếu của Swift để làm cho các lớp của bạn tạo mô tả của riêng chúng bằng cách sử dụng tiện ích mở rộng này:

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

4
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
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.