Interview: Schnell. Fragen und Antworten

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 Fragen
    Frage 1
    Betrachten 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 Antwort
    tutorial1.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 2
    Sie 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 Antwort
    Ja, 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 // : view2 is immutable 

    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 3
    Dieser 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 Antwort
    Swift 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 4
    Dieser 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 Antwort
    Adresse 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 Fragen
    Frage 1
    Was ist optional und welche Probleme lösen sie?

    die Antwort
    Mit 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 2
    Listen Sie kurz die Hauptunterschiede zwischen Struktur und Klasse auf .

    die Antwort
    Klassen unterstützen die Vererbung, Strukturen jedoch nicht.
    Klassen sind ein Referenztyp, Strukturen sind ein Werttyp.


    Frage 3
    Was sind Generika und wofür sind sie?

    die Antwort
    In 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") // true areIntEqual(1, 1) // true 

    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 4
    In einigen Fällen ist es nicht möglich, die implizit ausgepackten Optionen zu vermeiden. Wann und warum?

    die Antwort
    Die 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 5
    Welche 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 Antwort
    Das 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 Fragen
    Frage 1
    Was ist der Unterschied zwischen null und .none ?

    die Antwort
    Es 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 2
    Hier 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 Antwort
    ThermometerStruct 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 3
    Was wird dieser Code ausgeben und warum?

     var thing = "cars" let closure = { [thing] in print("I love \(thing)") } thing = "airplanes" closure() 


    die Antwort
    Es 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() // Prints: "I love airplanes" 



    Frage 4
    Dies 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]) //  3 


    Schreiben Sie diese Funktion als Array-Erweiterung neu, damit Sie sie folgendermaßen verwenden können:

     [1, 2, 3, 3].countUniques() //   3 


    Anmerkung des Übersetzers
    Etwas 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 5
    Hier 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 Antwort
    Die 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 6
    Schreiben Sie die Methode aus Frage 5 mit der if let-Anweisung neu .

    die Antwort
    Mit 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 Fragen
    Frage 1
    In Objective-C deklarieren Sie eine Konstante wie folgt:

     const int number = 0; 

    Und so in Swift:

     let number = 0 

    Was ist der Unterschied?

    die Antwort
    In 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 2
    Um 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 Antwort
    static 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() } // error: class method overrides a 'final' class method override static func illuminate() { super.illuminate() } } 



    Frage 3
    Ist es möglich, einem Typ mit der Erweiterung eine gespeicherte Eigenschaft hinzuzufügen? Wie oder warum nicht?

    die Antwort
    Nein, 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 4
    Was ist ein Protokoll in Swift?

    die Antwort
    Ein 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 Fragen
    Frage 1
    Angenommen, 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 Antwort
    Swift 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 2
    Swift 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 Antwort
    Die 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 3
    Der 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 Antwort
    In 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 4
    Der 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 Antwort
    Der 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 Fragen
    Frage 1
    Sind Verschlüsse ein Referenztyp oder ein Werttyp?

    die Antwort
    Verschlü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 2
    Sie 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 Antwort
    Hierfür gibt es einen Initialisierer:

     UInt(bitPattern: Int) 


    Und benutze:

     let myNegative = UInt(bitPattern: -1) 



    Frage 3
    Zirkelverweise in Swift beschreiben? Wie können sie behoben werden?

    die Antwort
    Zirkelverweise 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 4
    Mit 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 Antwort
    Wir haben das indirekte Schlüsselwort vergessen, das ähnliche rekursive Aufzählungsoptionen ermöglicht:

     enum List<T> { indirect case node(T, List<T>) } 




Source: https://habr.com/ru/post/de449410/


All Articles