يبلغ عمر لغة برمجة
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
ومع ذلك ، فإن 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")
باستخدام الوراثة ، فإنك تجمع بين وظيفتين في واحدة وفي نفس الوقت تضمن سلامة الكتابة:
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()
السؤال 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])
أعد كتابة هذه الوظيفة كملحق Array بحيث يمكنك استخدامها مثل هذا:
[1, 2, 3, 3].countUniques()
ملاحظة المترجمشيء مؤلم للغاية هو وظيفة وحشية. لماذا لا:
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() }
السؤال 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>) }