Apa yang setara dengan Swift dari - [deskripsi NSObject]?


163

Di Objective-C, seseorang dapat menambahkan descriptionmetode ke kelas mereka untuk membantu dalam debugging:

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

Kemudian di debugger, Anda bisa melakukan:

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

Apa yang setara di Swift? Output REPL Swift dapat membantu:

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

Tapi saya ingin mengganti perilaku ini untuk mencetak ke konsol:

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

Apakah ada cara untuk membersihkan printlnoutput ini ? Saya telah melihat Printableprotokolnya:

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

Saya pikir ini akan secara otomatis "dilihat" oleh printlntetapi tampaknya tidak terjadi:

  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)

Dan sebaliknya saya harus secara eksplisit memanggil deskripsi:

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

Apakah ada cara yang lebih baik?

Jawaban:


124

Untuk mengimplementasikan ini pada tipe Swift Anda harus mengimplementasikan CustomStringConvertibleprotokol dan kemudian juga mengimplementasikan properti string yang disebut description.

Sebagai contoh:

class MyClass: CustomStringConvertible {
    let foo = 42

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

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

Catatan: type(of: self)dapatkan jenis instance saat ini alih-alih secara eksplisit menulis 'MyClass'.


3
Great ditemukan! Saya akan mengajukan radar - println output "swift -i sample.swift" dan "swift sample.swift && sample" berbeda.
Jason

Terima kasih atas informasinya. Saya mencoba Printable di taman bermain dan memang itu tidak berfungsi sekarang. Bagus mendengarnya bekerja di aplikasi.
Tod Cunningham

Printable tidak bekerja di taman bermain, tetapi jika kelas turun dari NSObject
dar512

5
Di Swift 2.0 telah berubah menjadi CustomStringConvertible dan CustomDebugStringConvertible
Mike Vosseller

Juga, tidak ada masalah menggunakan CustomStringConvertible dan CustomDebugStringConvertible in Playground dengan Xcode 7.2
Nicholas Credli

54

Contoh penggunaan CustomStringConvertibledan CustomDebugStringConvertibleprotokol di Swift:

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

            ...
}

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

          ...
}

Yang dicetak:

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

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

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

Catatan: jika Anda memiliki kelas khusus yang tidak mewarisi dari kelas apa pun yang termasuk dalam pustaka UIKit atau Yayasan , maka buatlah itu mewarisi NSObjectkelas atau membuatnya sesuai CustomStringConvertibledan CustomDebugStringConvertibleprotokol.


fungsi harus dideklarasikan sebagai publik
Karsten

35

Cukup gunakan CustomStringConvertibledanvar description: String { return "Some string" }

bekerja di 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

Jawaban yang berkaitan dengan CustomStringConvertibleadalah cara untuk pergi. Secara pribadi, untuk menjaga definisi kelas (atau struct) sebersih mungkin, saya juga akan memisahkan kode deskripsi menjadi ekstensi yang terpisah:

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

Seperti dijelaskan di sini , Anda juga dapat menggunakan kemampuan refleksi Swift untuk membuat kelas Anda menghasilkan deskripsi sendiri dengan menggunakan ekstensi ini:

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.