[super init]

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • [super init]

    Hallo!

    Ich habe im Buch nicht ganz verstanden, warum man self = [super init] schreiben muss. Besser gesagt die Erklärung "Es könnte ja sein dass in NSObject bereits Instanzvariablen definiert wurden, die ebenfalls auf vernünftige Werte vorgesetzt werden müssen. Was heißt hier 'es könnte sein'? Es ist so!." NSObject wird doch gar nicht manipuliert; die Klasse Instrument ist doch ein Abkömmling von NSObject, hat also etwas vererbt bekommen. Oder verstehe ich da etwas falsch?

    Danke für eure Hilfe!

    PS: Was bedeutet "Bedankomat aktivieren" oben?
  • udjatauge schrieb:

    Hallo!

    Ich habe im Buch nicht ganz verstanden, warum man self = [super init] schreiben muss. Besser gesagt die Erklärung "Es könnte ja sein dass in NSObject bereits Instanzvariablen definiert wurden, die ebenfalls auf vernünftige Werte vorgesetzt werden müssen. Was heißt hier 'es könnte sein'? Es ist so!." NSObject wird doch gar nicht manipuliert; die Klasse Instrument ist doch ein Abkömmling von NSObject, hat also etwas vererbt bekommen. Oder verstehe ich da etwas falsch?

    Danke für eure Hilfe!

    PS: Was bedeutet "Bedankomat aktivieren" oben?

    Man muß nicht. Man kann, oder soll.

    Wenn man genau weiß, was [super init] tut, also insbesondere, dass es kein anderes Objekt als self zurückliefert (was manche Klassen-Cluster machen!), dann ist die Zuweisung überflüssig.

    Wenn man die Superklasse nicht genau kennt (also wenn man beispielsweise eine Subklasse von NSNumber anlegt), dann sollte man damit rechnen dass [super init] nicht self liefert...
  • udjatauge schrieb:

    Hallo!

    Ich habe im Buch nicht ganz verstanden, warum man self = [super init] schreiben muss. Besser gesagt die Erklärung "Es könnte ja sein dass in NSObject bereits Instanzvariablen definiert wurden, die ebenfalls auf vernünftige Werte vorgesetzt werden müssen. Was heißt hier 'es könnte sein'? Es ist so!." NSObject wird doch gar nicht manipuliert; die Klasse Instrument ist doch ein Abkömmling von NSObject, hat also etwas vererbt bekommen. Oder verstehe ich da etwas falsch?

    Danke für eure Hilfe!

    PS: Was bedeutet "Bedankomat aktivieren" oben?

    Woher weißt du das? Hast du die Sourcen der nächsten Version von Cocoa? Verspricht dir die Doku, dass NSObject unmanipuliert bleibt? Unter allen Umständen?

    Ich bleibe sogar beim Muss: Der Rückgabewert ist ein API-Vertrag. Was NSObject macht, ist gleichgültig. Das ändert nichts daran, dass der Vertrag der Vertrag ist. Alles andere ist Implementationsdetail. Das wird übrigens hartnäckig von Shipley verkannt.

    Und wie bereits von hns erwähnt, gibt es Klassen die davon Gebrauch machen, wie etwa das von ihm genannte NSNumber für Twintoning. Und die Doku verrät das als Implementationsdetail nicht:
    Creates and returns an NSNumber object containing a given value, treating it as a signed int.


    Du musst also ohne Zuweisung entweder Entwickler bei Apple sein oder NSKristallkugel instantiert haben.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    Woher weißt du das? Hast du die Sourcen der nächsten Version von Cocoa? Verspricht dir die Doku, dass NSObject unmanipuliert bleibt? Unter allen Umständen?

    Ich bleibe sogar beim Muss: Der Rückgabewert ist ein API-Vertrag. Was NSObject macht, ist gleichgültig. Das ändert nichts daran, dass der Vertrag der Vertrag ist. Alles andere ist Implementationsdetail. Das wird übrigens hartnäckig von Shipley verkannt.

    Kann ich nur unterstreichen.

    Selbst, wenn die Sourcen der Oberklasse bekannt sind, sollte mensch sich an den API-Vertrag halten. Erstens weil die Datenkapselung ein zentrales Paradigma der Objekt-Orientierung ist. Zweitens sollte die Unterklasse von Implementierungsdetails der Oberklasse unabhängig sein und drittens führt das andernfalls zu wackeligen Programmen, die mehr oder weniger nach dem Zufallsprinzip funktionieren.

    Wenn ich eine Klasse implementiere, interessiert mich die Implementierung irgendeiner anderen Klassen nicht die Bohne.
    „Meine Komplikation hatte eine Komplikation.“
  • Amin Negm-Awad schrieb:

    Woher weißt du das? Hast du die Sourcen der nächsten Version von Cocoa? Verspricht dir die Doku, dass NSObject unmanipuliert bleibt? Unter allen Umständen?
    Ist nach der Vererbung das neue Objekt nicht unabhängig von NSObject? Das, was ich nicht verstehe: "Warum muss ich initialisieren?" Du schreibst zwar: "Damit NSObject vernünftige Werte bekommt." Aber was soll ich darunter verstehen? NSObject ist ja schon programmiert.
    Was ist ein API-Vertrag bzw. Shipley?

    Was soll ich unter der Frage: "Woher weißt du das? Hast du die Sourcen der nächsten Version von Cocoa?" verstehen?
  • udjatauge schrieb:

    Amin Negm-Awad schrieb:

    Woher weißt du das? Hast du die Sourcen der nächsten Version von Cocoa? Verspricht dir die Doku, dass NSObject unmanipuliert bleibt? Unter allen Umständen?
    Ist nach der Vererbung das neue Objekt nicht unabhängig von NSObject? Das, was ich nicht verstehe: "Warum muss ich initialisieren?" Du schreibst zwar: "Damit NSObject vernünftige Werte bekommt." Aber was soll ich darunter verstehen? NSObject ist ja schon programmiert.
    Was ist ein API-Vertrag bzw. Shipley?

    Was soll ich unter der Frage: "Woher weißt du das? Hast du die Sourcen der nächsten Version von Cocoa?" verstehen?

    Ich denke wir müssen das ausführlicher erklären.

    Wenn Du Deine init-Methode schreibst, dann erwartet derjenige der ein Objekt Deiner Klasse anlegt, dass Dein Objekt komplett initialisiert wird und self, also die Referenz auf das nun initialisierte Objekt, zurückliefert (das ist mit API-vertrag gemeint).

    Da Du einen Teil der Instanzvariablen selbst definiert hast, initialisiert Du die natürlich. Aber Du hast (außer Du erstellst ein neues Root-Objekt) praktisch immer von einer anderen Klasse abgeleitet (das ist der von Dir nachgefragte Bezug zu NSObject - durch Vererbung ist Dein neues Object *auch* ein NSObject). Wenn Dein Objekt angelegt wird (alloc) dann hat es zwar alle Instanzvariablen, einschließlich derer die Du selbst definiert hast, aber auch die (Dir unbekannten) aller Oberklassen. Die müssen aber ebenfalls initialisiert werden sonst ist die Initialisierung unvollständig.

    Dazu rufst Du [super init] auf. Das kümmert sich nun um die Initialisierung aller Instanzvariablen der direkten Oberklasse. Und falls es selbst irgendwo abgeleitet wird, auch wieder die Ober-Oberklasse. D.h. die init's werden geschachtelt ausgeführt. Nun gibt es einen Sonderfall der viel Diskussion in vielen Blogs zur Folge hatte. Wenn Du von NSObject ableitest, ja dann ist klar dass Deine Oberklasse ein NSObject ist. Also rufst Du mit [super init] die (Dir völlig unbekannte) Init-Methode von NSObject auf. NSObject ist aber eine Root-Klasse, hat keine Instanz-Variablen, folglich auch offensichtlich nichts zu initialisieren und [super init] ist damit (scheinbar) überflüssig. (Einschub: besonders verwirrend ist dass man auch bei initWithCoder erst [super initWithCoder] aufrufen muß - aber NSObject diese Methode gar nicht implementiert, d.h. hier muß man es weglassen und sollte stattdessen [super init] aufrufen). Daher sind einige der Meinung dass self=[super init] mindestens in diesem Fall dass man direkt von NSObject ableitet überflüssig ist und die Performance um ca. 0.0000002% erhöht.

    Leider ist aber nirgends definiert was NSObject bei -init eigentlich tut. Dass es keine Instanzvariablen hat ist zwar klar, aber bedeutet nicht dass -init vielleicht intern doch irgendwas tut (Referenzcount? Locks anlegen? Debugging-Info? Performance-Messung? Garbage-Collector initialisieren?). Vielleicht macht es das alles heute nicht. D.h. Du wirst keinen Unterschied merken. Aber vielleicht kommt nächstes Jahr eine neue Version von Cocoa und Apple baut da etwas ganz tolles ein, was eben voraussetzt dass auch NSObject init aufgerufen wird. D.h. Dein Programm läuft plötzlich nicht mehr oder hat die neue Funktion nicht. Selbst nach Neu-Compilieren. Deshalb ist es einfach ein Gebot der Voraussicht, bei jeder Klasse [super init] aufzurufen. Ein anderer Fall ist dass Du irgendwann auf die Idee kommst Deine Klassenhierarchie neu zu sortieren. Und Deine bisher direkt von NSObject abgeleitete Klasse wird nun eine Unterklasse. Und Du (oder jemand anderes wenn Du das als Code-Snippet veröffentlichst) wunderst Dich warum -init der Oberklasse nie aufgerufen wird...

    Nochmal zum formalen Vertrags-Aspekt. Die Dokumentation schreibt
    Subclass versions of init need to incorporate the initialization code for the classes they inherit from, through a message to super:
    . D.h. "need to" ist eine Verpflichtung sich an das zu halten was ich oben rein technisch begründet habe, warum es sinnvoll ist.

    Dann gibts noch das andere Thema (ebenfalls in vielen Blogs diskutiert) warum init überhaupt ein Objekt zurückliefert und warum man self = [super init] schreiben muß und (void) [super init] nicht reicht.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von hns ()

  • udjatauge schrieb:

    Amin Negm-Awad schrieb:

    Woher weißt du das? Hast du die Sourcen der nächsten Version von Cocoa? Verspricht dir die Doku, dass NSObject unmanipuliert bleibt? Unter allen Umständen?
    Ist nach der Vererbung das neue Objekt nicht unabhängig von NSObject?

    Nein, es ist eine "Mixtur" aus dem Code in NSObject und in YourSubclass.

    Schau noch einmal auf die Abbildung auf Seite 210.

    udjatauge schrieb:

    Das, was ich nicht verstehe: "Warum muss ich initialisieren?" Du schreibst zwar: "Damit NSObject vernünftige Werte bekommt." Aber was soll ich darunter verstehen? NSObject ist ja schon programmiert.

    Ja, die Klasse ist schon programmiert. In deren -init steht deshalb irgendwelcher Code, der die Werte in der neuen Instanz setzt. genau so machst du es ja auch in deiner Subklasse. (In Wahrheit sind das bei NSObject 0 Werte, aber es geht ja ums Prinzip.)

    udjatauge schrieb:

    Was ist ein API-Vertrag bzw. Shipley?

    Vertrag ist einfach eine Vereinbarung zwischen dem Programmierer – hier – einer Klasse und dem Nutzer. Laut Dokumentation muss eine -init-Methode self als Rückgabewert liefern. Damit ist vereinbart – durch die Doku –, dass der Rückgabewert das self ist. Daran muss man sich nun halten.

    udjatauge schrieb:


    Was soll ich unter der Frage: "Woher weißt du das? Hast du die Sourcen der nächsten Version von Cocoa?" verstehen?

    Du sollst sie so verstehen, dass nur das gilt, was dokumentiert ist und alle anderen Überlegungen, die nicht darauf fußen, bei der nächsten Version perdu sein können.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?