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?

Jason
sumber

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

drewag
sumber
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.

Raja-Penyihir
sumber
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))"
}
Peter Ahlberg
sumber
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!"
Vince O'Sullivan
sumber
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
Peter Ahlberg
sumber
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
    }
}
Tuan Codesalot
sumber
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
neoneye
sumber