Als Java-Entwickler, der Apples Objective-C 2.0-Dokumentation liest: Ich frage mich, was " Senden einer Nachricht an Null " bedeutet - geschweige denn, wie nützlich es tatsächlich ist. Ein Auszug aus der Dokumentation:
Es gibt verschiedene Muster in Kakao, die diese Tatsache ausnutzen. Der von einer Nachricht an nil zurückgegebene Wert kann auch gültig sein:
- Wenn die Methode ein Objekt, einen beliebigen Zeigertyp, einen ganzzahligen Skalar mit einer Größe kleiner oder gleich sizeof (void *), ein float, ein double, ein long double oder ein long long zurückgibt, gibt eine an nil gesendete Nachricht 0 zurück .
- Wenn die Methode eine Struktur zurückgibt, die im Mac OS X ABI-Funktionsaufrufhandbuch definiert ist und in Registern zurückgegeben werden soll, gibt eine an nil gesendete Nachricht für jedes Feld in der Datenstruktur 0.0 zurück. Andere Strukturdatentypen werden nicht mit Nullen gefüllt.
- Wenn die Methode etwas anderes als die oben genannten Werttypen zurückgibt, ist der Rückgabewert einer an nil gesendeten Nachricht undefiniert.
Hat Java mein Gehirn unfähig gemacht, die obige Erklärung zu verstehen? Oder fehlt mir etwas, das dies so klar wie Glas macht?
Ich habe die Idee von Nachrichten / Empfängern in Objective-C, ich bin einfach verwirrt über einen Empfänger, der zufällig ist nil
.
objective-c
Ryan Delucchi
quelle
quelle
Antworten:
Nun, ich denke, es kann anhand eines sehr konstruierten Beispiels beschrieben werden. Angenommen, Sie haben eine Methode in Java, mit der alle Elemente in einer ArrayList ausgedruckt werden:
Wenn Sie diese Methode nun so aufrufen: someObject.foo (NULL); Sie werden wahrscheinlich eine NullPointerException erhalten, wenn versucht wird, auf list zuzugreifen, in diesem Fall beim Aufruf von list.size (); Jetzt würden Sie wahrscheinlich niemals someObject.foo (NULL) mit einem solchen NULL-Wert aufrufen. Möglicherweise haben Sie Ihre ArrayList jedoch von einer Methode erhalten, die NULL zurückgibt, wenn beim Generieren der ArrayList ein Fehler auftritt, z. B. someObject.foo (otherObject.getArrayList ()).
Natürlich haben Sie auch Probleme, wenn Sie so etwas tun:
In Objective-C haben wir nun die äquivalente Methode:
Nun, wenn wir den folgenden Code haben:
Wir haben die gleiche Situation, in der Java eine NullPointerException erzeugt. Auf das nil-Objekt wird zuerst mit [anArray count] zugegriffen. Anstatt jedoch eine NullPointerException auszulösen, gibt Objective-C gemäß den obigen Regeln einfach 0 zurück, sodass die Schleife nicht ausgeführt wird. Wenn wir die Schleife jedoch so einstellen, dass sie eine festgelegte Anzahl von Malen ausgeführt wird, senden wir zuerst eine Nachricht an anArray unter [anArray objectAtIndex: i]; Dies gibt auch 0 zurück, aber da objectAtIndex: einen Zeiger zurückgibt und ein Zeiger auf 0 nil / NULL ist, wird NSLog jedes Mal nil durch die Schleife übergeben. (Obwohl NSLog eine Funktion und keine Methode ist, wird es ausgegeben (null), wenn kein NSString übergeben wird.
In einigen Fällen ist es besser, eine NullPointerException zu haben, da Sie sofort feststellen können, dass etwas mit dem Programm nicht stimmt. Wenn Sie jedoch die Ausnahme nicht abfangen, stürzt das Programm ab. (In C führt der Versuch, NULL auf diese Weise zu dereferenzieren, zum Absturz des Programms.) In Objective-C verursacht es stattdessen möglicherweise nur ein falsches Laufzeitverhalten. Wenn Sie jedoch eine Methode haben, die nicht kaputt geht, wenn sie 0 / nil / NULL / eine auf Null gesetzte Struktur zurückgibt, müssen Sie nicht überprüfen, ob das Objekt oder die Parameter Null sind.
quelle
myObject->iVar
, wird es abstürzen, unabhängig davon, ob es C mit oder ohne Objekte ist. (Entschuldigung zu->
keine Objective-C-Operation mehr, sondern ein generischer C-Ismus.Eine Nachricht an die
nil
tut nichts und kehrtnil
,Nil
,NULL
,0
, oder0.0
.quelle
Alle anderen Beiträge sind korrekt, aber vielleicht ist es das Konzept, das hier wichtig ist.
In Objective-C-Methodenaufrufen ist jede Objektreferenz, die einen Selektor akzeptieren kann, ein gültiges Ziel für diesen Selektor.
Dies spart eine Menge von "Ist das Zielobjekt vom Typ X?" Code - Solange das empfangende Objekt den Selektor implementiert, spielt es absolut keine Rolle, um welche Klasse es sich handelt!
nil
ist ein NSObject, das jeden Selektor akzeptiert - es macht einfach nichts. Dadurch entfällt auch viel Code "Auf Null prüfen, Nachricht nicht senden, wenn wahr". (Das Konzept "Wenn es es akzeptiert, implementiert es es" ermöglicht es Ihnen auch, Protokolle zu erstellen , die Java-Schnittstellen ähneln: eine Erklärung, dass eine Klasse, die die angegebenen Methoden implementiert, dem Protokoll entspricht.)Der Grund dafür ist, Affencode zu eliminieren, der nichts anderes tut, als den Compiler bei Laune zu halten. Ja, Sie erhalten den Overhead eines weiteren Methodenaufrufs, sparen jedoch Programmiererzeit , was eine weitaus teurere Ressource als die CPU-Zeit ist. Darüber hinaus eliminieren Sie mehr Code und mehr bedingte Komplexität aus Ihrer Anwendung.
Klarstellung für Downvoter: Sie denken vielleicht, dass dies kein guter Weg ist, aber es ist, wie die Sprache implementiert wird, und es ist die empfohlene Programmiersprache in Objective-C (siehe die Stanford iPhone-Programmiervorträge).
quelle
Dies bedeutet, dass die Laufzeit keinen Fehler erzeugt, wenn objc_msgSend für den Nullzeiger aufgerufen wird. Stattdessen wird ein (oft nützlicher) Wert zurückgegeben. Nachrichten, die einen Nebeneffekt haben könnten, bewirken nichts.
Dies ist nützlich, da die meisten Standardwerte besser geeignet sind als ein Fehler. Beispielsweise:
Dh nil scheint das leere Array zu sein. Das Ausblenden einer Null-NSView-Referenz führt zu nichts. Praktisch, was?
quelle
Im Zitat aus der Dokumentation gibt es zwei getrennte Konzepte - vielleicht ist es besser, wenn die Dokumentation dies klarer macht:
Ersteres ist hier wahrscheinlich relevanter: Wenn Sie normalerweise Nachrichten an senden können,
nil
wird der Code einfacher - Sie müssen nicht überall nach Nullwerten suchen. Das kanonische Beispiel ist wahrscheinlich die Zugriffsmethode:Wenn das Senden von Nachrichten an
nil
nicht gültig war, wäre diese Methode komplexer - Sie würden zwei zusätzliche Kontrollen haben müssen , um sicherzustellen ,value
undnewValue
sind nichtnil
vor ihnen Nachrichten zu senden.Der letztere Punkt (die von einer Nachricht an zurückgegebenen Werte
nil
sind normalerweise ebenfalls gültig) fügt dem ersteren jedoch einen Multiplikatoreffekt hinzu. Beispielsweise:Dieser Code erfordert wiederum keine Überprüfung auf
nil
Werte und fließt natürlich ...Die zusätzliche Flexibilität, an die Nachrichten gesendet werden können, ist
nil
jedoch mit einigen Kosten verbunden. Es besteht die Möglichkeit, dass Sie irgendwann Code schreiben, der auf besondere Weise fehlschlägt, weil Sie die Möglichkeit eines Werts nicht berücksichtigt habennil
.quelle
Von Greg Parker ‚s - Website :
Wenn Sie LLVM Compiler 3.0 (Xcode 4.2) oder höher ausführen
quelle
Es bedeutet oft, dass Sie aus Sicherheitsgründen oft nicht überall nach null Objekten suchen müssen - insbesondere:
oder, wie bereits erwähnt, geben verschiedene Zähl- und Längenmethoden alle 0 zurück, wenn Sie einen Nullwert haben, sodass Sie nicht überall zusätzliche Überprüfungen für Null hinzufügen müssen:
oder dieses:
quelle
Denken Sie nicht an "der Empfänger ist Null"; Ich stimme zu, das ist ziemlich komisch. Wenn Sie eine Nachricht an nil senden, gibt es keinen Empfänger. Sie senden nur eine Nachricht an nichts.
Wie man damit umgeht, ist ein philosophischer Unterschied zwischen Java und Objective-C: In Java ist das ein Fehler; in Objective-C ist es ein No-Op.
quelle
ObjC-Nachrichten, die an nil gesendet werden und deren Rückgabewerte größer als sizeof (void *) sind, erzeugen auf PowerPC-Prozessoren undefinierte Werte. Darüber hinaus führen diese Nachrichten dazu, dass undefinierte Werte in Feldern von Strukturen zurückgegeben werden, deren Größe auch auf Intel-Prozessoren größer als 8 Byte ist. Vincent Gable hat dies in seinem Blog-Beitrag gut beschrieben
quelle
Ich glaube, keine der anderen Antworten hat dies klar erwähnt: Wenn Sie an Java gewöhnt sind, sollten Sie bedenken, dass Objective-C unter Mac OS X zwar Unterstützung für die Ausnahmebehandlung bietet, dies jedoch eine optionale Sprachfunktion sein kann Ein- / Ausschalten mit einem Compiler-Flag. Ich vermute, dass dieses Design des "Sendens von Nachrichten an
nil
ist sicher" vor der Aufnahme der Ausnahmebehandlungsunterstützung in die Sprache erfolgte und mit einem ähnlichen Ziel durchgeführt wurde: Methoden können zurückkehrennil
, um Fehler anzuzeigen, und da das Senden einer Nachricht annil
normalerweise zurückkehrtnil
Auf diese Weise kann sich die Fehleranzeige über Ihren Code ausbreiten, sodass Sie nicht bei jeder einzelnen Nachricht danach suchen müssen. Sie müssen nur an Stellen nachsehen, an denen es darauf ankommt. Ich persönlich denke, dass die Weitergabe und Behandlung von Ausnahmen ein besserer Weg ist, um dieses Ziel zu erreichen, aber möglicherweise sind nicht alle damit einverstanden. (Andererseits gefällt mir zum Beispiel nicht, dass Java deklarieren muss, welche Ausnahmen eine Methode auslösen darf, was Sie häufig dazu zwingt, Ausnahmedeklarationen syntaktisch im gesamten Code zu verbreiten. Dies ist jedoch eine andere Diskussion.)Ich habe eine ähnliche, aber längere Antwort auf die verwandte Frage "Ist es in Ziel C notwendig, zu behaupten, dass jede Objekterstellung erfolgreich war?" wenn Sie mehr Details wünschen.
quelle
nil
Rückkehr wurde häufig verwendet, um eine Kette in einen NO-Op kurzzuschließen.C steht für 0 als primitiv für primitive Werte und NULL für Zeiger (was in einem Zeigerkontext 0 entspricht).
Objective-C baut auf Cs Darstellung von Nichts auf, indem es Null hinzufügt. nil ist ein Objektzeiger auf nichts. Obwohl sie sich semantisch von NULL unterscheiden, sind sie technisch äquivalent zueinander.
Neu zugewiesene NSObjects beginnen ihr Leben mit einem auf 0 gesetzten Inhalt. Dies bedeutet, dass alle Zeiger, die das Objekt auf andere Objekte hat, mit Null beginnen, sodass es beispielsweise nicht erforderlich ist, in init-Methoden self. (Association) = nil zu setzen.
Das bemerkenswerteste Verhalten von nil ist jedoch, dass Nachrichten an ihn gesendet werden können.
In anderen Sprachen wie C ++ (oder Java) würde dies Ihr Programm zum Absturz bringen. In Objective-C gibt das Aufrufen einer Methode für nil jedoch einen Wert von Null zurück. Dies vereinfacht Ausdrücke erheblich, da nicht mehr nach Null gesucht werden muss, bevor etwas unternommen wird:
Wenn Sie wissen, wie Null in Objective-C funktioniert, ist dieser Komfort eine Funktion und kein lauernder Fehler in Ihrer Anwendung. Stellen Sie sicher, dass Sie sich vor Fällen schützen, in denen keine Werte unerwünscht sind, indem Sie entweder überprüfen und frühzeitig zurückkehren, um stillschweigend fehlzuschlagen, oder einen NSParameterAssert hinzufügen, um eine Ausnahme auszulösen.
Quelle: http://nshipster.com/nil/ https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html (Nachricht an nil senden).
quelle