تطوير الويب

إتقان أساسيات لغة Swift 6: types وoptionals ودوالّ

4 min de lecture

📘 الدليل الرئيسي: تطوير تطبيق iOS بـ Swift وSwiftUI: بانوراما 2026. هذا الدليل يُرَكِّز على اللغة؛ للبيئة والإعداد، راجع دليل تثبيت Xcode.

Swift لغة مكتَّبة، آمنة، مُختزَلة. سطحها التركيبي أصغر من C++ أو Java، ومعظم المفاهيم تُعَبَّر بشكل مباشر. يقطع هذا الدليل اللبنات الأساسية للغة في Playground Xcode: إعلان متغيّرات، أنواع أوّلية، optionals، دوالّ، closures، value types، وreference types. في النهاية، ستكون قد كتبت ونفّذت كلّ مثال، بما يكفي للانطلاق في SwiftUI دون التعثّر في الصياغة.

المتطلّبات

  • Xcode 26 مثبَّت على macOS Tahoe.
  • معرفة أساسية بالبرمجة بأيّ لغة مكتَّبة (متغيّرات، دوالّ، أنواع أوّلية).
  • الوقت المتوقّع: 60 إلى 90 دقيقة باتّباع كلّ الأمثلة.

الخطوة 1 — إنشاء Playground في Xcode

Playground ملفّ Swift تفاعلي يُنَفِّذ الكود مع الكتابة ويعرض النتائج في الهامش الأيمن. الأداة المثالية لتعلّم الصياغة دون تركيب مشروع app كامل.

في Xcode: File ← New ← Playground (⌥⇧⌘N). في المُحَدِّد، اختر macOS ← Blank ثم Next. سَمِّ الملفّ SwiftBasics.playground واحفظه في مجلّد عمل. Xcode يفتح الـ Playground بسطر مثال var greeting = "Hello, playground".

var greeting = "Hello, playground"
print(greeting)

الضغط على زرّ التشغيل على يسار السطر الأوّل (أو ⇧⏎) ينفّذ حتى هذا السطر. في الهامش الأيمن، القيمة "Hello, playground" تظهر بجوار الإعلان، وprint يعرض محتواه في console (View ← Debug Area ← Show Debug Area).

الخطوة 2 — متغيّرات، ثوابت، واستدلال الأنواع

Swift يُمَيِّز نمطَي تخزين: var للقيم القابلة للتعديل، let للثوابت. استدلال الأنواع يخمّن النوع عند حذفه، لكن يمكن تعليقه صراحة بـ : Type. التعليق الصريح مفيد حين لا يخمّن الاستدلال ما نريد.

let pi = 3.14159
var compteur = 0
compteur += 1

let nom: String = "Aïcha"
let age: Int = 28
let actif: Bool = true

السطر compteur += 1 يُجَمَّع لأنّ compteur مُعَلَن var. محاولة pi = 4.0 تُنتج الخطأ « Cannot assign to value: ‘pi’ is a ‘let’ constant ». الاصطلاح في Swift استعمال let افتراضيًّا والانتقال إلى var فقط عند الحاجة للتعديل. المُجَمِّع يُحذِّر من var كان يمكن إعلانها let.

الخطوة 3 — الأنواع الأوّلية والتحويلات

الأنواع الأساسية Int، Double، Float، String، Bool، إضافة إلى المجموعات Array، Dictionary، Set. Swift صارم بشأن التحويلات: لا يمكن جمع Int وDouble دون تحويل صريح.

let ageInt: Int = 28
let tauxDouble: Double = 1.5
// let invalide = ageInt + tauxDouble  // ❌ خطأ ترجمة
let valide: Double = Double(ageInt) + tauxDouble
print(valide)  // 29.5

السطر المُعَلَّق ينتج « Binary operator ‘+’ cannot be applied to operands of type ‘Int’ and ‘Double' ». هذه الصرامة تتفادى عائلة كاملة من أخطاء الدقّة الضمنية في JavaScript أو Python. القاعدة العملية: حوِّل صراحة عند خلط أنواع رقمية مختلفة، وفضِّل Double على Float ما لم تكن هناك حاجة محدّدة (Metal، حسابات علمية بدقّة بسيطة).

الخطوة 4 — Optionals: حجر الزاوية

لا مفهوم في Swift أهمّ من الـ optionals. الـ optional نوع يمكن أن يحوي قيمة أو nil. يُكتَب بإلحاق نوع بعلامة استفهام: String? تعني « سلسلة أو لا شيء ». المُجَمِّع يرفض التعامل مع قيمة optional كأنّها مضمونة الحضور — يجب تفريغها.

let prenomBrut: String? = "Mariam"
let prenomVide: String? = nil

// 1. optional binding بـ if let
if let prenom = prenomBrut {
    print("Bonjour \(prenom)")
} else {
    print("Pas de prénom")
}

// 2. guard let (خروج مبكر إن nil)
func saluer(_ p: String?) {
    guard let valeur = p else {
        print("Valeur manquante")
        return
    }
    print("Bonjour \(valeur)")
}
saluer(prenomVide)  // Valeur manquante

// 3. nil-coalescing
let affichage = prenomVide ?? "Anonyme"
print(affichage)  // Anonyme

// 4. optional chaining
let longueur = prenomBrut?.count
print(longueur as Any)  // Optional(6)

أربعة أنماط تتعايش. if let يدخل كتلة فقط إن كانت القيمة حاضرة. guard let يخرج مبكّرًا إن كانت غائبة — مفيد في بداية دالّة. ?? يُوَفِّر قيمة احتياط. ?. يُسَلسِل النداءات مع قصر إن nil. التفريغ القسري بـ ! موجود لكن يجب حصره على الحالات التي يستحيل فيها غياب القيمة — وإلّا يُسَبِّب crash بـ « Unexpectedly found nil while unwrapping an Optional value ».

الخطوة 5 — دوالّ ومعاملات مُسَمَّاة

دوالّ Swift تُعلَن بـ func. صياغة الاستدعاء تستعمل افتراضيًّا أسماء المعاملات كلصاقات، ممّا يُنتج استدعاءات شديدة القراءة. يمكن تسمية أو حذف لصاقة معامل حسب الحاجة.

func saluer(personne nom: String, en langue: String = "fr") -> String {
    switch langue {
    case "fr": return "Bonjour \(nom)"
    case "en": return "Hello \(nom)"
    case "es": return "Hola \(nom)"
    default: return nom
    }
}

let salutation = saluer(personne: "Fatou", en: "es")
print(salutation)  // Hola Fatou

// معامل بلا لصاقة: استعمل _
func carre(_ x: Int) -> Int { x * x }
print(carre(7))  // 49

اللصاقة الخارجية personne تظهر في الاستدعاء، بينما nom هو الاسم في الجسد. المعامل langue له قيمة افتراضية "fr"، ممّا يجعله اختياريًّا. الدالّة carre تستعمل _ لتُستدعى ببساطة carre(7). الكلمة return اختيارية لدالّة بتعبير واحد.

الخطوة 6 — Closures ودوالّ من رتبة أعلى

closure كتلة كود مجهولة الاسم تلتقط متغيّرات بيئتها. دوالّ المجموعات تستعملها بكثافة: map، filter، reduce، compactMap، sorted. السكّر التركيبي لـ Swift يجعل closures مُختصَرة جدًّا.

let nombres = [3, 1, 4, 1, 5, 9, 2, 6]

// شكل مُسهَب
let doubles = nombres.map({ (n: Int) -> Int in return n * 2 })

// شكل مُختصَر بالاستدلال
let triples = nombres.map { ${0 * 3 }

// filter + reduce متسلسلان
let sommeImpairs = nombres
    .filter { ${0 % 2 == 1 }
    .reduce(0, +)

print(doubles)       // [6, 2, 8, 2, 10, 18, 4, 12]
print(triples)       // [9, 3, 12, 3, 15, 27, 6, 18]
print(sommeImpairs)  // 19

الشكل المُختصَر يستغلّ ثلاث ميسّرات: استدلال الأنواع على المعاملات، trailing closure الذي يُخرج الـ closure من الأقواس، والأسماء المُختصَرة $0، $1… للمعاملات الموضعية. هذا الاختزال يجعل كود تحويل البيانات شديد القراءة بعد ألفة الاصطلاح.

الخطوة 7 — Structures وvalue types

الـ struct تُمَثِّل قيمًا: تُنسَخ عند الإسناد وتمرير المعاملات. هذه الدلالة تُلغي عائلة واسعة من أخطاء مشاركة الحالة. معظم أنواع Swift اليومية — بما فيها String، Array، Dictionary — هي structs.

struct Personne {
    var nom: String
    var age: Int

    func presentation() -> String {
        "(nom), (age) ans"
    }

    mutating func vieillir() {
        age += 1
    }
}

var alice = Personne(nom: "Alice", age: 30)
var copie = alice
copie.vieillir()

print(alice.age)  // 30 (غير معدَّل)
print(copie.age)  // 31

النسخة المُعَدَّلة لا تُؤَثِّر على الأصل لأنّه عند الإسناد var copie = alice، Swift يُكَرِّر البيانات. دالّة تُعَدِّل المثيل يجب وَسمها mutating؛ المُجَمِّع يمنع استدعاء vieillir() على let. هذا الانضباط يضمن معرفة أيّ مسار كود يستطيع تعديل قيمة.

الخطوة 8 — Classes وreference types

الـ class تُمَثِّل مراجع: عدّة متغيّرات يمكنها الإشارة إلى نفس المثيل. الـ classes ضرورية حين تلزم هويّة مشتركة، وراثة، أو دورة حياة مُتَحَكَّم بها عبر deinit. SwiftUI يستعمل قليلًا جدًّا من classes — معظم طبقة UI structs.

class Compteur {
    var valeur: Int = 0
    func incrementer() { valeur += 1 }
}

let a = Compteur()
let b = a
a.incrementer()

print(a.valeur)  // 1
print(b.valeur)  // 1 — نفس المثيل

a وb يُشيران إلى نفس المثيل؛ تعديل أحدهما يُؤَثِّر على الآخر. الدلالة المنتظرة لكائنات تُدير حالة مشتركة (موصِّل شبكي، cache). قاعدة الإبهام: ابدأ بـ struct؛ انتقل إلى class فقط حين تلزم الهويّة المشتركة، الوراثة، أو deinit بصرامة.

الخطوة 9 — Enum بقيم مُرتَبِطة

enums Swift تتجاوز بكثير enums C: كلّ حالة يمكنها حمل قيم مُرتَبِطة من نوع مختلف. هذه القوّة تُتيح نمذجة نتائج، حالات، رسائل بصرامة يُصادِق عليها المُجَمِّع عبر switch شامل.

enum ResultatReseau {
    case succes(donnees: Data)
    case echec(message: String, code: Int)
    case enCours
}

func traiter(_ r: ResultatReseau) {
    switch r {
    case .succes(let donnees):
        print("Reçu (donnees.count) octets")
    case .echec(let message, let code):
        print("Erreur (code) : (message)")
    case .enCours:
        print("En cours…")
    }
}

traiter(.echec(message: "Timeout", code: 504))

الـ switch شامل — إن نسيت حالة .enCours، المُجَمِّع يُشير « Switch must be exhaustive ». هذا الأمن يمنع إدخال حالة جديدة دون تحديث كلّ المُستهلِكين. لنتائج API، النوع Result<Succès, Erreur> من المكتبة القياسية يملأ هذا الدور بشكل أكثر اختزالًا.

الخطوة 10 — البروتوكولات والامتدادات

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

protocol Nommable {
    var nomComplet: String { get }
}

struct Etudiant: Nommable {
    let prenom: String
    let nom: String
    var nomComplet: String { "(prenom) (nom)" }
}

extension Etudiant {
    func saluer() -> String {
        "Bonjour, je suis (nomComplet)"
    }
}

let e = Etudiant(prenom: "Aminata", nom: "Diop")
print(e.saluer())  // Bonjour, je suis Aminata Diop

البروتوكول Nommable يتطلّب خاصية محسوبة nomComplet. الـ struct Etudiant تطابقها بتوفيرها. الامتداد يُضيف دالّة saluer() دون لمس الإعلان الأصلي — هذا النمط، السائد في Swift، يُتيح تنظيم الكود حسب الوظيفة لا حسب الهرمية.

أخطاء شائعة في البدء

الخطأ السبب الحلّ
« Value of optional type ‘String?’ must be unwrapped » التعامل المباشر مع optional استعمل if let، guard let، أو ?.
« Cannot assign to value: ‘x’ is a ‘let’ constant » محاولة تعديل ثابت أعلِن بـ var إن كان التعديل مقصودًا
« Switch must be exhaustive » حالة enum غير مغطّاة أضف الحالة الناقصة أو default:
« Type ‘X’ does not conform to protocol ‘Y' » متطلّب بروتوكول غير مُنَفَّذ تحقّق من التوقيع الدقيق (اسم، أنواع، get/set)
crash « Unexpectedly found nil » تفريغ قسري بـ ! على nil استبدل بـ ?.، ??، أو guard let
« Cannot use mutating member on immutable value » دالّة mutating على let أعلِن بـ var أو أزل mutating

أسئلة شائعة

هل يجب دائمًا تفضيل struct على class؟ افتراضيًّا نعم. struct تكفي 80% من نماذج العمل وتعرض دلالة قيمة أكثر قابلية للتنبّؤ. الانتقال إلى class مُبَرَّر حين تلزم هويّة مشتركة (singleton، موصِّل)، وراثة Objective-C (UIKit)، أو deinit لتحرير موارد خارجية.

كيف يقارَن Swift بـ Kotlin أو TypeScript؟ Swift يتقاسم مع Kotlin وTypeScript optionals، الدوالّ من الدرجة الأولى، استدلال الأنواع، وdata classes. فرقه الرئيسي غياب VM runtime: binary Swift أصلي، ممّا يُقلّل زمن إقلاع apps. لمطوّر Kotlin، الانتقال إلى Swift يتمّ في أيّام.

ما فائدة actor المُقَدَّم مع Swift Concurrency؟ actor نوع reference يُسَلسِل الوصول إلى حالته. أداة Swift لنمذجة كائن مشترك بين مهامّ متزامنة دون data race. لأوّل المشاريع، لا حاجة لـ actor؛ يصير مفيدًا حين نُشارك cache أو عميل شبكي بين مهامّ.

هل التفريغ القسري بـ ! سيّء دائمًا؟ لا، لكنّه نادرًا ما يكون مُبَرَّرًا. الحالات الشرعية @IBOutlet المرتبطة بـ storyboard، بعض التهيئات الجزئية، والتحويلات التي لا يمكن أن تفشل (مثل URL(string: "https://google.com")!). في كلّ الحالات الأخرى، guard let أو ?? أكثر أمنًا.

كيف نتعلّم Swift دون Mac؟ toolchain Swift يعمل على Linux وWindows للغة وحدها. على replit.com أو عبر Docker (image swift:6.3) يمكن تنفيذ Swift CLI. تطوير iOS ذاته يبقى حصريًّا لـ Mac بسبب Xcode والـ simulators.

أيّ كتاب رسمي للتعمّق؟ The Swift Programming Language المنشور من Apple هو المرجع القياسي: مجّاني، شامل، محدَّث مع كلّ release. لمسار أكثر سردًا، Tutorials SwiftUI الرسمي مكمِّل.

الأدلّة الموصى بها بعد هذا

مصادر رسمية

  • The Swift Programming Language — كتاب المرجع الرسمي.
  • Swift على Apple Developer — نقطة الدخول الرسمية.
  • ملاحظة release Swift 6.2 — التزامن القابل للتقريب، Span، embedded.
  • توثيق التزامن في Swift — actors، tasks، async/await.

🔝 العودة إلى الدليل الرئيسي.

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité