Wie kann ich den memberwise-Initialisierer standardmäßig für Strukturen in Swift veröffentlichen?

164

Ich habe ein schnelles Framework, das eine Struktur definiert:

public struct CollectionTO {
    var index: Order
    var title: String
    var description: String
}

Ich kann jedoch nicht den impliziten Element-Initialisierer aus einem anderen Projekt verwenden, das die Bibliothek importiert. Der Fehler ist, dass 'CollectionTO' nicht initialisiert werden kann, da keine zugänglichen Initialisierer vorhanden sind. Das heißt, es gibt dem standardmäßigen impliziten Element-Initialisierer nicht das öffentliche Schlüsselwort.

var collection1 = CollectionTO(index: 1, title: "New Releases", description: "All the new releases")

Ich muss meine eigene Init-Methode wie folgt hinzufügen:

public struct CollectionTO {
    var index: Order
    var title: String
    var description: String

    public init(index: Order, title: String, description: String) {
        self.index = index;
        self.title = title;
        self.description = description;
    }

}

... aber ich möchte lieber nicht, ob es einen anderen Weg gibt, den jemand kennt?

Bandejapaisa
quelle

Antworten:

268

Zitat des Handbuchs:

"Standardinitialisierer für Mitglieder für Strukturtypen Der Standardinitialisierer für Mitglieder für einen Strukturtyp wird als privat betrachtet, wenn eine der gespeicherten Eigenschaften der Struktur privat ist. Andernfalls verfügt der Initialisierer über eine interne Zugriffsebene.

Wie beim obigen Standardinitialisierer müssen Sie, wenn ein öffentlicher Strukturtyp bei Verwendung in einem anderen Modul mit einem Mitgliedsinitialisierer initialisiert werden soll, selbst einen öffentlichen Mitgliedsinitialisierer als Teil der Typdefinition bereitstellen. "

Auszug aus "The Swift Programming Language" , Abschnitt "Access Control" .

Bandejapaisa
quelle
283
Das ist nervig. :(
Dan Loewenherz
7
[ github.com/apple/swift-evolution/blob/master/proposals/… sagt: „Zitat von Chris Lattner: Das standardmäßige Initialisierungsverhalten von Swift in Bezug auf Mitglieder weist mindestens diese Mängel auf (IMO): 2) Zugriffskontrolle + Init in Bezug auf Mitglieder häufig erfordert, dass Sie es selbst implementieren “. Vielleicht ist es nur ein Mangel, der ohne besonderen Grund besteht. Es konnten keine weiteren Referenzen dazu gefunden werden.
Jano
8
@ DanLoewenherz Ja, das ist unpraktisch. Das Grundprinzip lautet: „Ein öffentlicher Typ hat standardmäßig interne Mitglieder, keine öffentlichen Mitglieder. Wenn Sie möchten, dass ein Typmitglied öffentlich ist, müssen Sie es explizit als solches markieren. Diese Anforderung stellt sicher, dass Sie sich für die Veröffentlichung der öffentlich zugänglichen API für einen Typ entscheiden, und vermeidet, dass die internen Funktionen eines Typs versehentlich als öffentliche API dargestellt werden. “ Auszug aus: Apple Inc. "Die schnelle Programmiersprache". iBooks. itun.es/gb/jEUH0.l
Bandejapaisa
18
Eine Compiler-Direktive wäre hilfreich, um das Standardverhalten zu überschreiben und öffentlich zu machen.
Bandejapaisa
9
Intern ist eine schreckliche Wahl für einen Standard, imo. Grundsätzlich wird garantiert, dass Sie beim ersten externen Referenzieren eines Moduls auf unerwartete Probleme stoßen. Warum nicht alles auf privat setzen, damit wir sofort erkennen können, wenn etwas nicht die richtige Zugriffsebene hat, und dann entscheiden, ob es öffentlich oder intern sein soll?
Devios1
71

Obwohl es nicht möglich ist, den Standardinitialisierer für Mitglieder zu verwenden, können Sie mit den folgenden Schritten schnell einen erstellen:

  1. Machen Sie das Objekt vorübergehend zu einer Klasse anstelle einer Struktur
  2. sparen
  3. Klicken Sie mit der rechten Maustaste auf den Klassennamen und wählen Sie Refactor -> Memberwise Initializer generieren
  4. Ändern Sie es wieder in eine Struktur
JP Aquino
quelle
brillant.
Ich
1
Funktioniert und motiviert auch dazu, Klassen anstelle von Strukturen zu verwenden. Youtube.com/watch?v=_V2sBURgUBI
Isaac Carol Weisberg
Das ist ein super Tipp !!
Peymankh
5
Ab Xcode 11 können Sie Generate Memberwise Initializer auch für Strukturen verwenden!
Brock Batsell
Fantastisch!!! Es ist nicht die richtige Antwort, aber ein sehr guter Tipp! Hat mir viel geholfen!
GuiOS
3

Bis Apple dies ändert und es weniger nervig macht, können Sie https://github.com/Bouke/SwiftInitializerGenerator (oder einen anderen) dieses Element für die Erstellung öffentlicher Initialisierer verwenden. Es wird also weniger Arbeit sein. Versuchte es und es funktioniert. Xcode Version 10.0, High Sierra 10.13.6

Zaporozhchenko Oleksandr
quelle
1

Wir haben jetzt ein Rubin-Juwel, um eine vollständige schnelle Datenmodelldatei zeilenweise zu analysieren und Modifikatoren für den öffentlichen Zugriff, Standardinitialisierer für öffentliche Mitglieder und andere Dinge in einer separaten, automatisch generierten, schnellen Ausgabe-Datei hinzuzufügen.

Dieses Juwel heißt swift_republic

Bitte lesen Sie die folgende Dokumentation, um dieses Juwel auszuführen:

https://github.com/mehul90/swift_republic

Mehul Parmar
quelle
1
Tolle Lösung !! Ich habe bereits einen Wrapper für erstellt swift_republicund funktioniert einwandfrei.
Md Shahed Hossain