Die Programmiersprache
Swift ist erst vier Jahre alt, wird jedoch bereits zur Hauptentwicklungssprache für iOS. Swift wurde zu Version 5.0 entwickelt und ist zu einer komplexen und leistungsstarken Sprache geworden, die sowohl einem objektorientierten als auch einem funktionalen Paradigma entspricht. Und mit jeder neuen Version werden noch mehr Funktionen hinzugefügt.
Aber wie gut kennst du Swift
wirklich ? In diesem Artikel finden Sie Beispielfragen für ein Swift-Interview.
Sie können diese Fragen verwenden, um Kandidaten zu interviewen, um ihr Wissen zu testen, oder Sie können Ihre eigenen testen. Wenn Sie die Antwort nicht kennen, machen Sie sich keine Sorgen: Auf jede Frage gibt es eine Antwort.
Die Fragen sind in drei Gruppen unterteilt:
- Anfänger : für Anfänger. Sie haben ein paar Bücher gelesen und Swift in Ihren eigenen Anwendungen angewendet.
- Mittelstufe : Geeignet für diejenigen, die sich wirklich für die Sprache interessieren. Sie haben bereits viel darüber gelesen und oft experimentiert.
- Fortgeschritten : Geeignet für die fortgeschrittensten Entwickler - diejenigen, die gerne in den Dschungel der Syntax eintauchen und fortgeschrittene Techniken anwenden möchten.
Für jedes Level gibt es zwei Arten von Fragen:
- geschrieben : Geeignet zum Testen per E-Mail, da sie das Schreiben von Code vorschlagen.
- mündlich : Kann verwendet werden, wenn Sie telefonieren oder persönlich sprechen, da es genügend Antworten in Worten gibt.
Halten Sie beim Lesen dieses Artikels den
Spielplatz offen, damit Sie den Code aus der Frage überprüfen können. Alle Antworten wurden auf
Xcode 10.2 und
Swift 5 getestet.
Anfänger
schriftliche FragenFrage 1Betrachten Sie den folgenden Code:
struct Tutorial { var difficulty: Int = 1 } var tutorial1 = Tutorial() var tutorial2 = tutorial1 tutorial2.difficulty = 2
Was sind die Werte von
tutorial1.difficulty und
tutorial2.difficulty ? Würde es einen Unterschied geben, wenn das
Tutorial eine Klasse wäre? Warum?
die Antworttutorial1.difficulty ist 1 und tutorial2.difficulty ist 2.
In Swift sind Strukturen Werttypen. Sie werden kopiert und nicht referenziert. Die folgende Zeile kopiert
tutorial1 und weist es
tutorial2 zu :
var tutorial2 = tutorial1
Änderungen an
Tutorial2 wirken sich nicht auf
Tutorial1 aus .
Wenn Tutorial eine Klasse wäre, wären
tutorial1.difficulty und
tutorial2.difficulty gleich 2. Klassen in Swift sind Referenztypen. Wenn Sie die Eigenschaft tutorial1 ändern, wird dieselbe Änderung für tutorial2 angezeigt - und umgekehrt.
Frage 2Sie haben
view1 mit
var und
view2 mit
let deklariert . Was ist der Unterschied und wird die letzte Zeile kompiliert?
import UIKit var view1 = UIView() view1.alpha = 0.5 let view2 = UIView() view2.alpha = 0.5
die AntwortJa, die letzte Zeile wird kompiliert.
view1 ist eine Variable, und Sie können ihren Wert einer neuen Instanz von UIView zuweisen. Mit
let können Sie einen Wert nur einmal zuweisen, sodass der folgende Code nicht kompiliert wird:
view2 = view1
UIView ist jedoch eine Klasse mit referenzieller Semantik, sodass Sie die Eigenschaften von view2 ändern können. Dies bedeutet, dass der Code
kompiliert wird .
Frage 3Dieser Code sortiert das Array alphabetisch. Vereinfachen Sie den Verschluss so weit wie möglich.
var animals = ["fish", "cat", "chicken", "dog"] animals.sort { (one: String, two: String) -> Bool in return one < two } print(animals)
die AntwortSwift
ermittelt automatisch die Art der Schließparameter und die Rückgabeart, sodass Sie sie
entfernen können :
animals.sort { (one, two) in return one < two }
Sie können Parameternamen mit der Notation
$ i ersetzen:
animals.sort { return $0 < $1 }
Abschlüsse, die aus einer einzelnen Anweisung bestehen, enthalten möglicherweise nicht das Schlüsselwort
return . Der Wert der zuletzt ausgeführten Anweisung wird zum Rückgabeergebnis des Abschlusses:
animals.sort { $0 < $1 }
Da Swift weiß, dass die Elemente des Arrays dem
Equatable- Protokoll entsprechen, können Sie einfach schreiben:
animals.sort(by: <)
Upd: hummingbirddj noch mehr vereinfacht:
In diesem Fall können Sie noch kürzer: animals.sort()
- Sortiert aufsteigend, funktioniert für Typen, die Comparable implementieren.
Frage 4Dieser Code erstellt zwei Klassen:
Adresse und
Person . Es werden auch zwei Instanzen der
Person- Klasse (
Ray und
Brian ) erstellt.
class Address { var fullAddress: String var city: String init(fullAddress: String, city: String) { self.fullAddress = fullAddress self.city = city } } class Person { var name: String var address: Address init(name: String, address: Address) { self.name = name self.address = address } } var headquarters = Address(fullAddress: "123 Tutorial Street", city: "Appletown") var ray = Person(name: "Ray", address: headquarters) var brian = Person(name: "Brian", address: headquarters)
Angenommen,
Brian ist an eine neue Adresse umgezogen und Sie möchten seinen Datensatz wie folgt aktualisieren:
brian.address.fullAddress = "148 Tutorial Street"
Dies wird kompiliert und läuft fehlerfrei. Wenn Sie jetzt die Adresse von
Ray überprüfen, werden Sie feststellen, dass er sich ebenfalls
„bewegt“ hat .
Was ist hier passiert und wie können wir das beheben?
die AntwortAdresse ist eine Klasse und hat Referenzsemantik . Das Hauptquartier ist also dieselbe Instanz der Klasse, die Ray und Brian gemeinsam haben. Durch Ändern des Hauptsitzes wird die Adresse von beiden geändert.
Um dies zu beheben, können Sie eine neue Instanz der Adressklasse erstellen und Brian zuweisen oder Adresse als Struktur anstelle einer Klasse deklarieren .
mündliche FragenFrage 1Was ist
optional und welche Probleme lösen sie?
die AntwortMit optional kann eine Variable eines beliebigen Typs eine Situation ohne Wert darstellen . In Objective-C war "kein Wert" nur in Referenztypen mit dem speziellen Nullwert verfügbar. Werttypen wie int oder float hatten diese Funktion nicht.
Swift hat das Konzept "kein Wert" auf Werttypen erweitert. Die optionale Variable kann entweder einen Wert oder Null enthalten , was auf das Fehlen eines Werts hinweist.
Frage 2Listen Sie kurz die Hauptunterschiede zwischen
Struktur und
Klasse auf .
die AntwortKlassen unterstützen die Vererbung, Strukturen jedoch nicht.
Klassen sind ein Referenztyp, Strukturen sind ein Werttyp.
Frage 3Was sind
Generika und wofür sind sie?
die AntwortIn Swift können Sie
Generika in Klassen, Strukturen und Aufzählungen verwenden.
Generika beheben das Problem der Codeduplizierung. Wenn Sie eine Methode haben, die Parameter eines Typs akzeptiert, müssen Sie manchmal Code duplizieren, um mit Parametern eines anderen Typs zu arbeiten.
In diesem Code ist die zweite Funktion beispielsweise ein "Klon" der ersten, außer dass sie Zeichenfolgenparameter und keine Ganzzahlen enthält.
func areIntEqual(_ x: Int, _ y: Int) -> Bool { return x == y } func areStringsEqual(_ x: String, _ y: String) -> Bool { return x == y } areStringsEqual("ray", "ray")
Mit Generika kombinieren Sie zwei Funktionen in einer und sorgen gleichzeitig für die Typensicherheit:
func areTheyEqual<T: Equatable>(_ x: T, _ y: T) -> Bool { return x == y } areTheyEqual("ray", "ray") areTheyEqual(1, 1)
Da Sie die Gleichheit testen, beschränken Sie die Typen auf diejenigen, die dem
Equatable- Protokoll entsprechen. Dieser Code liefert das gewünschte Ergebnis und verhindert die Übertragung von Parametern des falschen Typs.
Frage 4In einigen Fällen ist es nicht möglich, die implizit
ausgepackten Optionen zu vermeiden. Wann und warum?
die AntwortDie häufigsten Gründe für die Verwendung implizit ausgepackter Optionen sind:
- Wenn Sie eine Eigenschaft nicht initialisieren können, die zum Zeitpunkt der Erstellung nicht Null ist. Ein typisches Beispiel ist die Steckdose bei Interface Builder, die immer nach ihrem Eigentümer initialisiert wird. In diesem speziellen Fall, wenn in Interface Builder alles richtig konfiguriert ist, ist sichergestellt, dass die Steckdose vor der Verwendung nicht Null ist.
- um das Problem der Schleife starker Referenzen zu lösen, wenn zwei Instanzen von Klassen aufeinander verweisen und eine Nicht-Null-Referenz auf eine andere Instanz erforderlich ist. In diesem Fall markieren Sie den Link auf der einen Seite als nicht besessen und verwenden auf der anderen Seite die implizite optionale Erweiterung.
Frage 5Welche Möglichkeiten zur optionalen Bereitstellung gibt es? Bewerten Sie sie in Bezug auf die Sicherheit.
var x : String? = "Test"
Hinweis: Nur 7 Möglichkeiten.
die AntwortDas erzwungene Auspacken ist unsicher.
let a: String = x!
Die implizite Bereitstellung beim Deklarieren einer Variablen ist unsicher.
var a = x!
Optionale Bindung ist sicher.
if let a = x { print("x was successfully unwrapped and is = \(a)") }
Optionale Verkettung ist sicher.
let a = x?.count
Kein Koaleszenzbetreiber ist sicher.
let a = x ?? ""
Die
Guard- Anweisung ist sicher.
guard let a = x else { return }
Optionales Muster - sicher.
if case let a? = x { print(a) }
Mittelstufe
schriftliche FragenFrage 1Was ist der Unterschied zwischen
null und
.none ?
die AntwortEs gibt keinen Unterschied,
Optional.none (kurz
.none ) und
nil sind gleichwertig.
Tatsächlich gibt die folgende Anweisung
true zurück :
nil == .none
Die Verwendung von
Null wird allgemein akzeptiert und empfohlen.
Frage 2Hier ist ein Thermometermodell in Form von Klasse und Struktur. Der Compiler beschwert sich über die letzte Zeile. Was ist da falsch?
public class ThermometerClass { private(set) var temperature: Double = 0.0 public func registerTemperature(_ temperature: Double) { self.temperature = temperature } } let thermometerClass = ThermometerClass() thermometerClass.registerTemperature(56.0) public struct ThermometerStruct { private(set) var temperature: Double = 0.0 public mutating func registerTemperature(_ temperature: Double) { self.temperature = temperature } } let thermometerStruct = ThermometerStruct() thermometerStruct.registerTemperature(56.0)
die AntwortThermometerStruct wird korrekt mit einer Mutationsfunktion deklariert, um die interne Variable zu ändern. Der Compiler beschwert sich, dass Sie die registerTemperature- Methode der Instanz aufrufen, die mit let erstellt wurde , sodass diese Instanz unveränderlich ist. Durch Ändern von let in var wird der Kompilierungsfehler behoben.
In Strukturen sollten Sie Methoden, die interne Variablen ändern, als mutierend markieren. Sie können diese Methoden jedoch nicht mit einer unveränderlichen Instanz aufrufen.
Frage 3Was wird dieser Code ausgeben und warum?
var thing = "cars" let closure = { [thing] in print("I love \(thing)") } thing = "airplanes" closure()
die AntwortEs wird gedruckt: Ich liebe Autos. Die Erfassungsliste erstellt eine Kopie der Variablen, wenn der Abschluss deklariert wird. Dies bedeutet, dass die erfasste Variable ihren Wert auch nach dem Zuweisen eines neuen Werts nicht ändert.
Wenn Sie die Erfassungsliste im Abschluss weglassen, verwendet der Compiler den Link und nicht die Kopie. Der Abschlussaufruf spiegelt die Änderung der Variablen wider:
var thing = "cars" let closure = { print("I love \(thing)") } thing = "airplanes" closure()
Frage 4Dies ist eine Funktion, die die Anzahl der eindeutigen Werte in einem Array zählt:
func countUniques<T: Comparable>(_ array: Array<T>) -> Int { let sorted = array.sorted() let initial: (T?, Int) = (.none, 0) let reduced = sorted.reduce(initial) { ($1, $0.0 == $1 ? $0.1 : $0.1 + 1) } return reduced.1 }
Es wird sortiert verwendet, daher werden nur Typen verwendet, die dem Comparable-Protokoll entsprechen.
Sie können es so nennen:
countUniques([1, 2, 3, 3])
Schreiben Sie diese Funktion als Array-Erweiterung neu, damit Sie sie folgendermaßen verwenden können:
[1, 2, 3, 3].countUniques()
Anmerkung des ÜbersetzersEtwas zu Schmerzhaftes ist eine monströse Funktion. Warum nicht:
func countUniques<T: Hashable>(_ array: Array<T>) -> Int { return Set(array).count }
die Antwort extension Array where Element: Comparable { func countUniques() -> Int { let sortedValues = sorted() let initial: (Element?, Int) = (.none, 0) let reduced = sortedValues.reduce(initial) { ($1, $0.0 == $1 ? $0.1 : $0.1 + 1) } return reduced.1 } }
Frage 5Hier ist eine Funktion, die zwei optionale Doppel teilt. Es gibt drei Bedingungen, die erfüllt sein müssen:
- Dividende sollte nicht Null sein
- Der Teiler sollte nicht Null sein
- Der Divisor darf nicht 0 sein
func divide(_ dividend: Double?, by divisor: Double?) -> Double? { if dividend == nil { return nil } if divisor == nil { return nil } if divisor == 0 { return nil } return dividend! / divisor! }
Schreiben Sie diese Funktion mit der
Guard- Anweisung neu und ohne erzwungenes Entpacken.
die AntwortDie in Swift 2.0 eingeführte
Guard- Anweisung bietet einen Exit, wenn die Bedingung nicht erfüllt ist. Hier ist ein Beispiel:
guard dividend != nil else { return nil }
Sie können die Guard-Anweisung auch für die
optionale Bindung verwenden . Danach ist die erweiterte Variable
außerhalb der Guard-Anweisung verfügbar:
guard let dividend = dividend else { return .none }
Sie können die Funktion also folgendermaßen umschreiben:
func divide(_ dividend: Double?, by divisor: Double?) -> Double? { guard let dividend = dividend else { return nil } guard let divisor = divisor else { return nil } guard divisor != 0 else { return nil } return dividend / divisor }
Beachten Sie das Fehlen eines erzwungenen Entpackens, da wir Dividende und Divisor bereits entpackt und in nicht optionale unveränderliche Variablen eingefügt haben.
Beachten Sie auch, dass das Ergebnis der entpackten Optionen in der Guard-Anweisung auch außerhalb der Guard-Anweisung verfügbar ist.
Sie können die Funktion weiter vereinfachen, indem Sie Guard-Anweisungen gruppieren:
func divide(_ dividend: Double?, by divisor: Double?) -> Double? { guard let dividend = dividend, let divisor = divisor, divisor != 0 else { return nil } return dividend / divisor }
Frage 6Schreiben Sie die Methode aus Frage 5 mit der
if let-Anweisung neu .
die AntwortMit der if let-Anweisung können Sie Optionen entpacken und diesen Wert in diesem Codeblock verwenden. Außerhalb davon sind diese Werte nicht verfügbar.
func divide(_ dividend: Double?, by divisor: Double?) -> Double? { if let dividend = dividend, let divisor = divisor, divisor != 0 { return dividend / divisor } else { return nil } }
mündliche FragenFrage 1In Objective-C deklarieren Sie eine Konstante wie folgt:
const int number = 0;
Und so in Swift:
let number = 0
Was ist der Unterschied?
die AntwortIn
Objective-C wird
zur Kompilierungszeit eine Konstante
mit einem Wert initialisiert
, der an dieser Stelle bekannt sein sollte.
Ein mit
let erstellter unveränderlicher Wert ist eine
zur Laufzeit definierte Konstante. Sie können es mit einem statischen oder dynamischen Ausdruck initialisieren. Deshalb können wir dies tun:
let higherNumber = number + 5
Bitte beachten Sie, dass eine solche Zuordnung nur einmal durchgeführt werden kann.
Frage 2Um eine statische Eigenschaft oder Funktion für Werttypen zu deklarieren, wird der
statische Modifikator verwendet. Hier ist ein Beispiel für die Struktur:
struct Sun { static func illuminate() {} }
Und für Klassen ist es möglich,
statische oder
Klassenmodifikatoren zu verwenden . Das Ergebnis ist das gleiche, aber es gibt einen Unterschied. Beschreibe es.
die Antwortstatic macht eine Eigenschaft oder Funktion statisch und
nicht überlappend . Die Verwendung von class
überschreibt eine Eigenschaft oder Funktion.
Hier schwört der Compiler bei dem Versuch,
illuminate () zu überschreiben:
class Star { class func spin() {} static func illuminate() {} } class Sun : Star { override class func spin() { super.spin() }
Frage 3Ist es möglich, einem Typ mit der
Erweiterung eine
gespeicherte Eigenschaft hinzuzufügen? Wie oder warum nicht?
die AntwortNein, das ist nicht möglich. Wir können die Erweiterung verwenden, um einem vorhandenen Typ neues Verhalten hinzuzufügen, aber wir können den Typ selbst oder seine Schnittstelle nicht ändern. Zum Speichern der neuen gespeicherten Eigenschaft benötigen wir zusätzlichen Speicher, und die Erweiterung kann dies nicht tun.
Frage 4Was ist ein Protokoll in Swift?
die AntwortEin Protokoll ist ein Typ, der eine Übersicht über Methoden, Eigenschaften usw. definiert. Eine Klasse, Struktur oder Aufzählung kann ein Protokoll benötigen, um all dies zu implementieren. Das Protokoll selbst implementiert die Funktionalität nicht, sondern definiert sie.
Erweitert
schriftliche FragenFrage 1Angenommen, wir haben eine Struktur, die das Modell eines Thermometers definiert:
public struct Thermometer { public var temperature: Double public init(temperature: Double) { self.temperature = temperature } }
Um eine Instanz zu erstellen, schreiben wir:
var t: Thermometer = Thermometer(temperature:56.8)
Aber so etwas wäre viel bequemer:
var thermometer: Thermometer = 56.8
Ist es möglich? Wie?
die AntwortSwift definiert Protokolle, mit denen Sie einen Typ mithilfe von Literalen durch Zuweisung initialisieren können. Durch Anwenden des entsprechenden Protokolls und Bereitstellen eines öffentlichen Initialisierers wird die Initialisierung mithilfe von Literalen ermöglicht. Im Fall von Thermometer implementieren wir
ExpressibleByFloatLiteral :
extension Thermometer: ExpressibleByFloatLiteral { public init(floatLiteral value: FloatLiteralType) { self.init(temperature: value) } }
Jetzt können wir eine Instanz wie folgt erstellen:
var thermometer: Thermometer = 56.8
Frage 2Swift verfügt über eine Reihe vordefinierter Operatoren für arithmetische und logische Operationen. Sie können damit auch eigene Operatoren erstellen, sowohl unäre als auch binäre.
Definieren und implementieren Sie Ihren eigenen Potenzierungsoperator (^^) gemäß den folgenden Anforderungen:
- nimmt zwei int als Parameter
- Gibt das Ergebnis des Erhöhens des ersten Parameters auf die Potenz des zweiten zurück
- verarbeitet die Reihenfolge der algebraischen Operationen korrekt
- ignoriert mögliche Überlauffehler
die AntwortDie Erstellung eines neuen Operators erfolgt in zwei Schritten: Ankündigung und Implementierung.
Die Deklaration verwendet das
Operator- Schlüsselwort, um den Typ (unär oder binär) anzugeben, um die Zeichenfolge des neuen Operators, seine Assoziativität und den Vorrang der Ausführung anzugeben.
Hier ist der Operator ^^ und sein Typ ist infix (binär). Assoziativität ist richtig.
Swift hat kein vordefiniertes Dienstalter für die Potenzierung. In der Algebra muss die Exponentiation vor der Multiplikation / Division berechnet werden. Daher erstellen wir eine benutzerdefinierte Ausführungsreihenfolge, indem wir die Exponentiation höher als die Multiplikation platzieren.
Diese Ankündigung:
precedencegroup ExponentPrecedence { higherThan: MultiplicationPrecedence associativity: right } infix operator ^^: ExponentPrecedence
Dies ist die Implementierung:
func ^^(base: Int, exponent: Int) -> Int { let l = Double(base) let r = Double(exponent) let p = pow(l, r) return Int(p) }
Frage 3Der folgende Code definiert die Struktur von
Pizza und das
Pizzeria- Protokoll mit einer Erweiterung für die Standardimplementierung der Methode
makeMargherita () :
struct Pizza { let ingredients: [String] } protocol Pizzeria { func makePizza(_ ingredients: [String]) -> Pizza func makeMargherita() -> Pizza } extension Pizzeria { func makeMargherita() -> Pizza { return makePizza(["tomato", "mozzarella"]) } }
Jetzt definieren wir das Restaurant
Lombardis :
struct Lombardis: Pizzeria { func makePizza(_ ingredients: [String]) -> Pizza { return Pizza(ingredients: ingredients) } func makeMargherita() -> Pizza { return makePizza(["tomato", "basil", "mozzarella"]) } }
Der folgende Code erstellt zwei Instanzen von
Lombardis . Welche von ihnen machen Margarita mit Basilikum?
let lombardis1: Pizzeria = Lombardis() let lombardis2: Lombardis = Lombardis() lombardis1.makeMargherita() lombardis2.makeMargherita()
die AntwortIn beiden. Das
Pizzeria- Protokoll deklariert die Methode
makeMargherita () und bietet eine Standardimplementierung. Die
Lombardis- Implementierung überschreibt die Standardmethode. Da wir die Methode im Protokoll an zwei Stellen deklariert haben, wird die korrekte Implementierung aufgerufen.
Was aber, wenn das Protokoll die Methode
makeMargherita () nicht deklariert hat und die Erweiterung weiterhin die Standardimplementierung wie
folgt bereitstellt :
protocol Pizzeria { func makePizza(_ ingredients: [String]) -> Pizza } extension Pizzeria { func makeMargherita() -> Pizza { return makePizza(["tomato", "mozzarella"]) } }
In diesem Fall hätte nur lombardis2 Pizza mit Basilikum, während lombardis1 keine Pizza hätte, da die in der Erweiterung definierte Methode verwendet würde.
Frage 4Der folgende Code wird nicht kompiliert. Können Sie erklären, was mit ihm los ist? Schlagen Sie Lösungen für das Problem vor.
struct Kitten { } func showKitten(kitten: Kitten?) { guard let k = kitten else { print("There is no kitten") } print(k) }
Hinweis: Es gibt drei Möglichkeiten, um den Fehler zu beheben.
die AntwortDer
else- Block der
Guard- Anweisung erfordert eine Exit-Option, entweder mit
return ,
Auslösen einer Ausnahme oder Aufrufen von
@noreturn . Die einfachste Lösung besteht darin, eine
return-Anweisung hinzuzufügen.
func showKitten(kitten: Kitten?) { guard let k = kitten else { print("There is no kitten") return } print(k) }
Diese Lösung löst eine Ausnahme aus:
enum KittenError: Error { case NoKitten } struct Kitten { } func showKitten(kitten: Kitten?) throws { guard let k = kitten else { print("There is no kitten") throw KittenError.NoKitten } print(k) } try showKitten(kitten: nil)
Schließlich ist hier der Aufruf von
fatalError () , der Funktion
@noreturn .
struct Kitten { } func showKitten(kitten: Kitten?) { guard let k = kitten else { print("There is no kitten") fatalError() } print(k) }
mündliche FragenFrage 1Sind Verschlüsse ein Referenztyp oder ein Werttyp?
die AntwortVerschlüsse sind ein Referenztyp. Wenn Sie einer Variablen einen Abschluss zuweisen und ihn dann in eine andere Variable kopieren, kopieren Sie den Link zu demselben Abschluss und seiner Erfassungsliste.
Frage 2Sie verwenden den
UInt- Typ, um eine vorzeichenlose Ganzzahl zu speichern. Es implementiert einen Initialisierer zum Konvertieren von einem Ganzen mit einem Vorzeichen:
init(_ value: Int)
Der folgende Code wird jedoch nicht kompiliert, wenn Sie einen negativen Wert angeben:
let myNegative = UInt(-1)
Vorzeichenbehaftete Ganzzahlen können per Definition nicht negativ sein. Es ist jedoch möglich, die Darstellung einer negativen Zahl im Speicher zu verwenden, um sie in eine vorzeichenlose Zahl zu übersetzen.
Wie kann ich eine negative Ganzzahl in UInt konvertieren, während ihre Darstellung im Speicher bleibt?
die AntwortHierfür gibt es einen Initialisierer:
UInt(bitPattern: Int)
Und benutze:
let myNegative = UInt(bitPattern: -1)
Frage 3Zirkelverweise in Swift beschreiben? Wie können sie behoben werden?
die AntwortZirkelverweise treten auf, wenn zwei Instanzen einen starken Bezug zueinander haben, was zu einem Speicherverlust führt, da keine dieser Instanzen freigegeben werden kann. Eine Instanz kann nicht freigegeben werden, solange noch starke Verweise darauf vorhanden sind, aber eine Instanz enthält die andere.
Dies kann behoben werden, indem der Link auf einer Seite durch Angabe des Schlüsselworts schwach oder nicht besessen ersetzt wird .
Frage 4Mit Swift können Sie rekursive Aufzählungen erstellen. Hier ist ein Beispiel für eine solche Aufzählung, die eine Knotenvariante mit zwei assoziativen Typen, T und Liste, enthält:
enum List<T> { case node(T, List<T>) }
Es wird ein Kompilierungsfehler auftreten. Was haben wir vermisst?
die AntwortWir haben das
indirekte Schlüsselwort vergessen, das ähnliche rekursive Aufzählungsoptionen ermöglicht:
enum List<T> { indirect case node(T, List<T>) }