Was ist das Swift-Äquivalent von - [NSObject description]?


163

In Objective-C können Sie descriptionihrer Klasse eine Methode hinzufügen , um das Debuggen zu erleichtern:

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

Dann können Sie im Debugger Folgendes tun:

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

Was ist das Äquivalent in Swift? Die REPL-Ausgabe von Swift kann hilfreich sein:

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

Aber ich möchte dieses Verhalten beim Drucken auf der Konsole überschreiben:

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

Gibt es eine Möglichkeit, diese printlnAusgabe zu bereinigen ? Ich habe das PrintableProtokoll gesehen:

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

Ich dachte, dies würde automatisch von "gesehen" werden, printlnaber es scheint nicht der Fall zu sein:

  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)

Und stattdessen muss ich die Beschreibung explizit aufrufen:

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

Gibt es einen besseren Weg?

Antworten:


124

Um dies auf einem Swift-Typ zu implementieren, müssen Sie das CustomStringConvertibleProtokoll implementieren und anschließend auch eine aufgerufene Zeichenfolgeeigenschaft implementieren description.

Beispielsweise:

class MyClass: CustomStringConvertible {
    let foo = 42

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

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

Hinweis: type(of: self)Ruft den Typ der aktuellen Instanzen ab, anstatt explizit 'MyClass' zu schreiben.


3
Toller Fund! Ich werde ein Radar einreichen - Druckausgabe von "swift -i sample.swift" und "swift sample.swift && sample" unterscheiden sich.
Jason

Danke für die Infos dazu. Ich habe Printable auf einem Spielplatz ausprobiert und tatsächlich funktioniert es momentan nicht. Gut, dass es in einer App funktioniert.
Tod Cunningham

Printable funktioniert auf dem Spielplatz, aber wenn die Klasse von NSObject abstammt
dar512

5
In Swift 2.0 wurde es in CustomStringConvertible und CustomDebugStringConvertible geändert
Mike Vosseller

Es gibt auch kein Problem bei der Verwendung von CustomStringConvertible und CustomDebugStringConvertible auf dem Spielplatz mit Xcode 7.2
Nicholas Credli

54

Anwendungsbeispiel CustomStringConvertibleund CustomDebugStringConvertibleProtokolle in 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" 
    }

            ...
}

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

          ...
}

Welcher Ausdruck:

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

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

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

Hinweis: Wenn Sie eine benutzerdefinierte Klasse haben, die von keiner in UIKit- oder Foundation- Bibliotheken enthaltenen NSObjectKlasse erbt, erben Sie sie von der Klasse oder passen Sie sie an CustomStringConvertibleund CustomDebugStringConvertibleProtokolle an.


Die Funktion muss als öffentlich deklariert werden
Karsten

35

Verwenden Sie einfach CustomStringConvertibleundvar description: String { return "Some string" }

funktioniert in 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

Die Antworten in Bezug auf CustomStringConvertiblesind der richtige Weg. Um die Definition der Klasse (oder Struktur) so sauber wie möglich zu halten, würde ich den Beschreibungscode auch in eine separate Erweiterung aufteilen:

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

Wie hier beschrieben , können Sie auch die Reflexionsfunktionen von Swift verwenden, damit Ihre Klassen mithilfe dieser Erweiterung eine eigene Beschreibung generieren:

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.