مقابلة: سويفت. سؤال وجواب

يبلغ عمر لغة برمجة Swift أربعة أعوام فقط ، لكنها أصبحت بالفعل لغة التطوير الرئيسية لنظام التشغيل iOS. تطور إلى الإصدار 5.0 ، أصبح Swift لغة معقدة وقوية تلبي نموذجًا موجهًا للكائنات ونموذجًا وظيفيًا. ومع كل إصدار جديد ، فإنه يضيف المزيد من الميزات.

لكن إلى أي مدى تعرف سويفت حقًا ؟ في هذه المقالة ، ستجد أسئلة نموذجية لمقابلة سويفت.

يمكنك استخدام هذه الأسئلة لمقابلة المرشحين لاختبار معرفتهم أو يمكنك اختبار معلوماتك الخاصة. إذا كنت لا تعرف الإجابة ، فلا تقلق: فهناك إجابة لكل سؤال.

يتم تقسيم الأسئلة إلى ثلاث مجموعات:

  • المبتدئين : للمبتدئين. تقرأ بضعة كتب وطبقت تطبيق سويفت في تطبيقاتك الخاصة.
  • متوسط : مناسب لأولئك الذين يهتمون حقًا باللغة. لقد قرأت بالفعل الكثير عن ذلك وتجربته غالبًا.
  • متقدم : مناسب للمطورين الأكثر تقدمًا - أولئك الذين يحبون الدخول في غابة بناء الجملة واستخدام التقنيات المتقدمة.

هناك نوعان من الأسئلة لكل مستوى:

  • مكتوبة : مناسبة للاختبار عن طريق البريد الإلكتروني ، لأنها تشير إلى كتابة التعليمات البرمجية.
  • شفهيًا : يمكن استخدامه عند التحدث على الهاتف أو شخصيًا ، حيث توجد إجابة كافية بالكلمات.

أثناء قراءة هذا المقال ، اجعل الملعب مفتوحًا حتى تتمكن من التحقق من الكود من السؤال. تم اختبار جميع الإجابات على Xcode 10.2 و Swift 5 .

  • مبتدئ


    أسئلة مكتوبة
    السؤال 1
    النظر في التعليمات البرمجية التالية:

    struct Tutorial { var difficulty: Int = 1 } var tutorial1 = Tutorial() var tutorial2 = tutorial1 tutorial2.difficulty = 2 

    ما هي قيم tutorial1.difficulty و tutorial2.difficulty ؟ هل سيكون هناك أي فرق إذا كان البرنامج التعليمي صفًا؟ لماذا؟

    الجواب
    tutorial1.difficulty هو 1 ، و tutorial2.difficulty هو 2.

    في Swift ، تكون الهياكل أنواع قيمة. يتم نسخها ، وليس الرجوع إليها. السطر التالي بنسخ tutorial1 وتعيينه إلى tutorial2 :

     var tutorial2 = tutorial1 

    لا تؤثر التغييرات في tutorial2 على tutorial1 .

    إذا كان البرنامج التعليمي عبارة عن فصل دراسي ، فسوف تساوي tutorial1.difficulty و tutorial2.difficulty 2. والفئات في Swift هي أنواع مرجعية. عندما تقوم بتغيير خاصية tutorial1 ، سترى نفس التغيير لبرنامج tutorial2 - والعكس بالعكس.


    السؤال 2
    أعلنت view1 مع var و view2 مع اسمحوا . ما هو الفرق ويتم تجميع السطر الأخير؟

     import UIKit var view1 = UIView() view1.alpha = 0.5 let view2 = UIView() view2.alpha = 0.5 //   ? 

    الجواب
    نعم ، يتم تجميع السطر الأخير. view1 متغير ، ويمكنك تعيين قيمته لمثيل جديد لـ UIView. باستخدام اسمحوا ، يمكنك فقط تعيين قيمة مرة واحدة ، لذلك لا يتم ترجمة التعليمات البرمجية التالية:

     view2 = view1 // : view2 is immutable 

    ومع ذلك ، فإن UIView هي فئة ذات دلالات مرجعية ، بحيث يمكنك تغيير خصائص view2 - مما يعني أن الشفرة ستترجم .

    السؤال 3
    يفرز هذا الكود الصفيف أبجديًا. تبسيط الإغلاق قدر الإمكان.

     var animals = ["fish", "cat", "chicken", "dog"] animals.sort { (one: String, two: String) -> Bool in return one < two } print(animals) 

    الجواب
    يحدد Swift تلقائيًا نوع معلمات الإغلاق ونوع الإرجاع ، بحيث يمكنك إزالتها :

     animals.sort { (one, two) in return one < two } 

    يمكنك استبدال أسماء المعلمات باستخدام الترميز $ i :

     animals.sort { return $0 < $1 } 

    قد لا تحتوي الإغلاقات التي تتكون من عبارة واحدة على الكلمة الأساسية للعودة . تصبح قيمة العبارة الأخيرة المنفذة نتيجة الإغلاق للإغلاق:

     animals.sort { $0 < $1 } 

    أخيرًا ، نظرًا لأن Swift يعرف أن عناصر المصفوفة تتوافق مع بروتوكول Equatable ، يمكنك ببساطة كتابة:

     animals.sort(by: <) 


    تحديث: hummingbirddj المبسطة أكثر:
    في هذه الحالة ، يمكنك حتى أقصر:
      animals.sort() 
    - فرز تصاعدي ، يعمل مع الأنواع التي تنفذ للمقارنة.


    السؤال 4
    ينشئ هذا الرمز فئتين: العنوان والشخص . كما تم إنشاء حالتين من فئة الشخص ( راي وبريان ).

     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) 

    لنفترض أن برايان انتقل إلى عنوان جديد وتريد تحديث سجله على النحو التالي:

     brian.address.fullAddress = "148 Tutorial Street" 

    هذا يجمع ويدير دون أخطاء. ولكن ، إذا قمت بالتحقق الآن من عنوان راي ، فستشاهد أنه "انتقل" أيضًا.

    ما حدث هنا وكيف يمكننا إصلاحه؟

    الجواب
    العنوان فئة وله دلالات مرجعية . وبالتالي ، فإن المقر الرئيسي هو نفس مثيل الفئة التي تشترك فيها راي وبريان. سيؤدي تغيير المقر إلى تغيير عنوان كليهما.
    لإصلاح ذلك ، يمكنك إنشاء مثيل جديد لفئة العنوان وتعيينها إلى براين ، أو إعلان العنوان كبنية بدلاً من الفصل الدراسي .

    أسئلة شفهية
    السؤال 1
    ما هو اختياري وما هي المشاكل التي يحلونها؟

    الجواب
    اختياري يسمح للمتغير من أي نوع بتقديم موقف " بلا قيمة ". في الهدف- C ، "لا توجد قيمة" كانت متاحة فقط في أنواع المراجع باستخدام قيمة الصفر الخاصة. أنواع القيم ، مثل int أو float ، لا تملك هذه الإمكانية.
    وسعت سويفت مفهوم "لا قيمة" لأنواع القيمة. يمكن أن يحتوي المتغير الاختياري على قيمة أو لا شيء ، مما يشير إلى عدم وجود قيمة.


    السؤال 2
    اذكر باختصار الاختلافات الرئيسية بين الهيكل والطبقة .

    الجواب
    الطبقات تدعم الميراث ، ولكن الهياكل لا تدعم ذلك.
    الفئات هي نوع مرجعي ، والهياكل هي نوع قيمة.


    السؤال 3
    ما هي الأدوية وما هي؟

    الجواب
    في Swift ، يمكنك استخدام الوراثة في الفصول والبنى والتعدادات.

    الوراثة إصلاح مشكلة الازدواجية رمز. إذا كان لديك طريقة تقبل المعلمات من نوع واحد ، في بعض الأحيان تضطر إلى تكرار التعليمات البرمجية للعمل مع المعلمات من نوع آخر.

    على سبيل المثال ، في هذا الرمز ، تكون الوظيفة الثانية "استنساخ" للأول ، باستثناء أنه يحتوي على معلمات سلسلة ، وليس عددًا صحيحًا.

     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 

    باستخدام الوراثة ، فإنك تجمع بين وظيفتين في واحدة وفي نفس الوقت تضمن سلامة الكتابة:

     func areTheyEqual<T: Equatable>(_ x: T, _ y: T) -> Bool { return x == y } areTheyEqual("ray", "ray") areTheyEqual(1, 1) 

    نظرًا لأنك تختبر المساواة ، فأنت تقيد الأنواع على تلك التي تتوافق مع بروتوكول Equatable . يوفر هذا الرمز النتيجة المرغوبة ويمنع نقل المعلمات من النوع الخطأ.


    السؤال 4
    في بعض الحالات ، لن يكون من الممكن تجنب الاختيارات غير المضمنة ضمنيًا. متى ولماذا؟

    الجواب
    الأسباب الأكثر شيوعًا لاستخدام الاختيارات غير المضمنة ضمنيًا هي:

    • عندما لا يمكنك تهيئة خاصية ليست خالية في وقت الإنشاء. مثال نموذجي هو المنفذ في Interface Builder ، والذي تتم تهيئته دائمًا بعد مالكه. في هذه الحالة الخاصة ، إذا كان كل شيء قد تم تكوينه بشكل صحيح في Interface Builder ، فأنت مضمون في أن المنفذ غير صفري قبل استخدامه.
    • لحل مشكلة حلقة المراجع القوية ، عندما تشير حالتان من الطبقات إلى بعضهما البعض وتكون الإشارة غير الصفرية إلى مثيل آخر مطلوبة. في هذه الحالة ، تقوم بوضع علامة على الرابط الموجود على جانب واحد باعتباره غير مملوك ، وعلى الجانب الآخر تستخدم توسيعًا اختياريًا ضمنيًا.


    السؤال 5
    ما هي بعض الطرق لنشر اختياري؟ معدل لهم من حيث الأمن.

     var x : String? = "Test" 

    تلميح: فقط 7 طرق.

    الجواب
    إلغاء القسري غير آمن.

     let a: String = x! 

    النشر الضمني عند التصريح عن متغير غير آمن.

     var a = x! 

    الربط الاختياري آمن.

     if let a = x { print("x was successfully unwrapped and is = \(a)") } 

    تسلسل اختياري آمن.

     let a = x?.count 

    لا يوجد عامل تشغيل ائتلاف آمن.

     let a = x ?? "" 

    بيان الحرس آمن.

     guard let a = x else { return } 

    نمط اختياري - آمن.

     if case let a? = x { print(a) } 




  • متوسط


    أسئلة مكتوبة
    السؤال 1
    ما هو الفرق بين لا شيء و.

    الجواب
    لا يوجد فرق ، اختياري. بلا (لفترة وجيزة. لا شيء ) ولا شيء معادلان .
    في الواقع ، سيعود العبارة التالية صحيحاً :

     nil == .none 


    استخدام النيل غير مقبول بشكل عام ويوصى به.


    السؤال 2
    هنا نموذج ميزان حرارة في شكل فئة وهيكل. المترجم يشكو من السطر الأخير. ما هو الخطأ هناك؟

     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) 

    الجواب
    تم إعلان ThermometerStruct بشكل صحيح مع وظيفة متحولة لتغيير المتغير الداخلي. المترجم يشكو من أنك تقوم باستدعاء طريقة registerTemperature للمثيل الذي تم إنشاؤه باستخدام let ، لذلك هذا المثيل غير قابل للتغيير. سيؤدي تغيير السماح لـ var إلى إصلاح خطأ التحويل البرمجي.

    في الهياكل ، يجب عليك وضع علامة على الطرق التي تعدل المتغيرات الداخلية كتحور ، لكن لا يمكنك استدعاء هذه الطرق باستخدام مثيل ثابت.


    السؤال 3
    ما سوف يخرج هذا الرمز ولماذا؟

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


    الجواب
    سيتم طباعتها: أنا أحب السيارات. ستقوم قائمة الالتقاط بإنشاء نسخة من المتغير عند إعلان الإغلاق. هذا يعني أن المتغير الذي تم التقاطه لن يغير قيمته ، حتى بعد تعيين قيمة جديدة.

    إذا حذفت قائمة الالتقاط في الإغلاق ، فسيستخدم المترجم الرابط وليس النسخة. استدعاء الإغلاق سيعكس التغيير في المتغير:

     var thing = "cars" let closure = { print("I love \(thing)") } thing = "airplanes" closure() // Prints: "I love airplanes" 



    السؤال 4
    هذه دالة تحسب عدد القيم الفريدة في صفيف:

     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 } 

    يستخدم الفرز ، لذلك يستخدم فقط الأنواع التي تتوافق مع البروتوكول المقارن.

    يمكنك تسميتها مثل هذا:

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


    أعد كتابة هذه الوظيفة كملحق Array بحيث يمكنك استخدامها مثل هذا:

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


    ملاحظة المترجم
    شيء مؤلم للغاية هو وظيفة وحشية. لماذا لا:

     func countUniques<T: Hashable>(_ array: Array<T>) -> Int { return Set(array).count } 


    الجواب
     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 } } 



    السؤال 5
    هذه دالة تقسم الزوجين الاختياريين. هناك ثلاثة شروط يجب الوفاء بها:
    • لا ينبغي أن يكون الربح لا شيء
    • يجب أن لا يكون المقسوم صفراً
    • يجب ألا يكون المقسوم على 0


     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! } 

    أعد كتابة هذه الوظيفة باستخدام بيان الحماية وعدم استخدام الضغط القسري.
    الجواب
    يوفر بيان الحماية الذي تم تقديمه في Swift 2.0 خروجًا إذا لم يتم الوفاء بالشرط. هنا مثال:

     guard dividend != nil else { return nil } 


    يمكنك أيضًا استخدام بيان الحماية للربط الاختياري ، وبعد ذلك سيتوفر المتغير الموسع خارج بيان الحماية :

     guard let dividend = dividend else { return .none } 


    حتى تتمكن من إعادة كتابة الوظيفة مثل هذا:

     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 } 

    لاحظ عدم وجود تفريغ قسري ، نظرًا لأننا قمنا بالفعل بتفريغ العائد والمقسوم عليه ووضعه في متغيرات ثابتة غير اختيارية.

    لاحظ أيضًا أن نتيجة الاختيارات غير المعبأة في بيان الحماية متاحة أيضًا خارج بيان الحماية.

    يمكنك تبسيط الوظيفة من خلال تجميع بيانات الحماية:

     func divide(_ dividend: Double?, by divisor: Double?) -> Double? { guard let dividend = dividend, let divisor = divisor, divisor != 0 else { return nil } return dividend / divisor } 



    السؤال 6
    أعد كتابة الطريقة من السؤال 5 باستخدام عبارة if let .

    الجواب
    تسمح لك عبارة if let بإلغاء تحميل الخيارات الاختيارية واستخدام هذه القيمة داخل مجموعة التعليمات البرمجية هذه. خارجها ، هذه القيم لن تكون متاحة.

     func divide(_ dividend: Double?, by divisor: Double?) -> Double? { if let dividend = dividend, let divisor = divisor, divisor != 0 { return dividend / divisor } else { return nil } } 




    أسئلة شفهية
    السؤال 1
    في Objective-C ، تعلن ثابت مثل هذا:

     const int number = 0; 

    وهكذا في سويفت:

     let number = 0 

    ما هو الفرق؟

    الجواب
    في Objective-C ، تتم تهيئة ثابت في وقت الترجمة مع قيمة يجب أن تكون معروفة في هذه المرحلة.

    القيمة الثابتة التي تم إنشاؤها باستخدام let هي قيمة ثابتة محددة في وقت التشغيل . يمكنك تهيئته بتعبير ثابت أو ديناميكي. لذلك ، يمكننا أن نفعل هذا:

     let higherNumber = number + 5 


    يرجى ملاحظة أن هذه المهمة لا يمكن القيام بها إلا مرة واحدة.


    السؤال 2
    لإعلان خاصية ثابتة أو دالة لأنواع القيمة ، يتم استخدام المعدل الثابت . فيما يلي مثال للبنية:

     struct Sun { static func illuminate() {} } 

    وبالنسبة للفئات ، من الممكن استخدام المعدلات الثابتة أو المعدلات الصفية . النتيجة هي نفسها ، ولكن هناك فرق. صفها.

    الجواب
    ثابت يجعل خاصية أو وظيفة ثابتة وغير متداخلة . باستخدام فئة سوف تتجاوز خاصية أو وظيفة.

    هنا سوف يقسم المترجم في محاولة لتجاوز illuminate () :

     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() } } 



    السؤال 3
    هل من الممكن إضافة خاصية مخزنة إلى نوع باستخدام ملحق ؟ كيف أم لا؟

    الجواب
    لا ، هذا غير ممكن. يمكننا استخدام الإضافة لإضافة سلوك جديد إلى نوع موجود ، لكن لا يمكننا تغيير النوع نفسه أو واجهته. لتخزين الخاصية المخزنة الجديدة ، نحتاج إلى ذاكرة إضافية ، ولا يمكن للإضافة القيام بذلك.


    السؤال 4
    ما هو البروتوكول في سويفت؟

    الجواب
    البروتوكول هو نوع يحدد الخطوط العريضة للطرق ، الخصائص ، إلخ. يمكن للفئة أو البنية أو التعداد أخذ بروتوكول لتنفيذ كل هذا. لا يقوم البروتوكول نفسه بتنفيذ الوظيفة ، ولكنه يعرّفها.



  • متقدم


    أسئلة مكتوبة
    السؤال 1
    لنفترض أن لدينا هيكلًا يحدد نموذج مقياس الحرارة:

     public struct Thermometer { public var temperature: Double public init(temperature: Double) { self.temperature = temperature } } 

    لإنشاء مثيل ، نكتب:

     var t: Thermometer = Thermometer(temperature:56.8) 

    ولكن شيء مثل هذا سيكون أكثر ملاءمة:

     var thermometer: Thermometer = 56.8 

    هل هذا ممكن؟ كيف؟

    الجواب
    يحدد Swift البروتوكولات التي تسمح لك بتهيئة نوع باستخدام القيم الحرفية حسب الواجب. سيسمح تطبيق البروتوكول المناسب وتوفير مُهيئ عام للتهيئة باستخدام القيم الحرفية. في حالة مقياس الحرارة ، ننفذ ExpressibleByFloatLiteral :

     extension Thermometer: ExpressibleByFloatLiteral { public init(floatLiteral value: FloatLiteralType) { self.init(temperature: value) } } 


    الآن يمكننا إنشاء مثيل مثل هذا:

     var thermometer: Thermometer = 56.8 



    السؤال 2
    يحتوي Swift على مجموعة من العوامل المحددة مسبقًا للعمليات الحسابية والمنطقية. كما يسمح لك بإنشاء مشغلي الخاصة بك ، سواء أحادي وثنائي.

    قم بتحديد وتنفيذ مشغل الأس الخاص بك (^^) وفقًا للمتطلبات التالية:
    • يأخذ اثنين من كثافة العمليات كمعلمات
    • إرجاع نتيجة رفع المعلمة الأولى إلى قوة الثانية
    • يعالج بشكل صحيح ترتيب العمليات الجبرية
    • يتجاهل أخطاء تجاوز السعة المحتملة


    الجواب
    يتم إنشاء مشغل جديد على مرحلتين: الإعلان والتنفيذ.

    يستخدم الإعلان الكلمة الأساسية للمشغل لتحديد النوع (أحادي أو ثنائي) ، لتحديد تسلسل أحرف المشغل الجديد ، ورابطيته وأسبقية التنفيذ.

    المشغل هنا هو ^ ^ ونوعه هو infix (ثنائي). الارتباط هو الصحيح.

    لا يحتوي سويفت على الأقدمية المحددة مسبقًا للتسوية. في الجبر ، يجب حساب الأس قبل الضرب / القسمة. وبالتالي ، نقوم بإنشاء أمر تنفيذ مخصص عن طريق وضع الأس على أعلى من الضرب.

    هذا الإعلان:

     precedencegroup ExponentPrecedence { higherThan: MultiplicationPrecedence associativity: right } infix operator ^^: ExponentPrecedence 


    هذا هو التنفيذ:

     func ^^(base: Int, exponent: Int) -> Int { let l = Double(base) let r = Double(exponent) let p = pow(l, r) return Int(p) } 



    السؤال 3
    تعرّف التعليمة البرمجية التالية بنية بيتزا وبروتوكول بيتزا بملحق للتطبيق الافتراضي لطريقة 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"]) } } 


    الآن نحدد مطعم لومبارديس :

     struct Lombardis: Pizzeria { func makePizza(_ ingredients: [String]) -> Pizza { return Pizza(ingredients: ingredients) } func makeMargherita() -> Pizza { return makePizza(["tomato", "basil", "mozzarella"]) } } 

    ينشئ التعليمة البرمجية التالية مثيلين من Lombardis . أي منهم يصنع المارجريتا بالريحان؟

     let lombardis1: Pizzeria = Lombardis() let lombardis2: Lombardis = Lombardis() lombardis1.makeMargherita() lombardis2.makeMargherita() 


    الجواب
    في كليهما. يعلن بروتوكول Pizzeria طريقة makeMargherita () ويوفر تطبيقًا افتراضيًا. يتجاوز تطبيق Lombardis الطريقة الافتراضية. نظرًا لأننا أعلنا الطريقة في البروتوكول في مكانين ، فسيتم استدعاء التطبيق الصحيح.

    ولكن ماذا لو لم يعلن البروتوكول طريقة makeMargherita () ، ولا يزال التمديد يوفر التنفيذ الافتراضي ، مثل هذا:

     protocol Pizzeria { func makePizza(_ ingredients: [String]) -> Pizza } extension Pizzeria { func makeMargherita() -> Pizza { return makePizza(["tomato", "mozzarella"]) } } 

    في هذه الحالة ، سيكون فقط lombardis2 البيتزا مع الريحان ، بينما lombardis1 لن يكون لديه بيتزا ، لأنه سيستخدم الطريقة المحددة في التمديد.


    السؤال 4
    لا يتم ترجمة التعليمات البرمجية التالية. هل يمكنك شرح ما هو الخطأ معه؟ اقترح حلول للمشكلة.

     struct Kitten { } func showKitten(kitten: Kitten?) { guard let k = kitten else { print("There is no kitten") } print(k) } 

    تلميح: هناك ثلاث طرق لإصلاح الخطأ.


    الجواب
    تتطلب الكتلة الأخرى من بيان الحماية خيار الخروج ، إما باستخدام الإرجاع أو الاستثناء أو الاتصال على noreturn . الحل الأبسط هو إضافة بيان الإرجاع .

     func showKitten(kitten: Kitten?) { guard let k = kitten else { print("There is no kitten") return } print(k) } 

    هذا الحل سوف يلقي استثناء:

     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) 


    أخيرًا ، ها هي استدعاء fatalError () ، وظيفة @ noreturn .

     struct Kitten { } func showKitten(kitten: Kitten?) { guard let k = kitten else { print("There is no kitten") fatalError() } print(k) } 




    أسئلة شفهية
    السؤال 1
    هل عمليات الإغلاق هي نوع المرجع أو نوع القيمة؟

    الجواب
    الإغلاقات هي نوع مرجعي. إذا قمت بتعيين إغلاق لمتغير ثم قمت بنسخه إلى متغير آخر ، فإنك تنسخ الرابط إلى نفس الإغلاق وقائمة الالتقاط الخاصة به.


    السؤال 2
    يمكنك استخدام نوع UInt لتخزين عدد صحيح غير موقعة. ينفذ مُهيئ للتحويل من علامة برمجية:

     init(_ value: Int) 

    ومع ذلك ، لا يتم ترجمة التعليمات البرمجية التالية إذا حددت قيمة سالبة:

     let myNegative = UInt(-1) 

    أعداد صحيحة موقعة ، بحكم التعريف ، لا يمكن أن تكون سالبة. ومع ذلك ، من الممكن استخدام تمثيل رقم سالب في الذاكرة لترجمته إلى رقم غير موقع.

    كيف يمكنني تحويل عدد صحيح سالب إلى UInt مع الحفاظ على تمثيله في الذاكرة؟

    الجواب
    يوجد مُهيئ لهذا:

     UInt(bitPattern: Int) 


    واستخدام:

     let myNegative = UInt(bitPattern: -1) 



    السؤال 3
    وصف المراجع الدائرية في سويفت؟ كيف يمكن أن تكون ثابتة؟

    الجواب
    تحدث المراجع الدائرية عندما تحتوي حالتان على مرجع قوي لبعضهما البعض ، مما يؤدي إلى تسرب للذاكرة بسبب عدم إمكانية تحرير أي من هذه الحالات. لا يمكن تحرير مثيل بينما لا تزال هناك إشارات قوية إليه ، ولكن هناك مثيل واحد يحمل الآخر.

    يمكن حل ذلك عن طريق استبدال الرابط على جانب واحد عن طريق تحديد الكلمة الرئيسية ضعيفة أو غير مملوكة .


    السؤال 4
    يسمح لك Swift بإنشاء تعدادات متكررة. فيما يلي مثال على هذا التعداد الذي يحتوي على متغير Node مع نوعين من الجمعيات ، T و List:

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

    سيكون هناك خطأ في الترجمة. ماذا افتقدنا؟

    الجواب
    لقد نسينا الكلمة الرئيسية غير المباشرة ، والتي تتيح خيارات التعداد العودية المماثلة:

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




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


All Articles