Swift: صفوف Swift والاختياريات: دليل عملي لـ Tuple وOptional

الصفوف تتيح لك تجميع قيم متعددة معًا؛ الاختياريات تتيح لك معالجة القيم الفارغة بأمان. يعالج هذا الدرس تحديين أساسيين للبيانات في تطوير Swift.

1. ما ستتعلمه


2. قصة حقيقية: مطور iOS

(1) نقطة الألم: تعطل التطبيق عندما أعادت API قيمة فارغة

Alice هي مطورة iOS تبني صفحة ملف مستخدم. استدعت API الخلفية لجلب بيانات المستخدم:

SWIFT
// Simulated API response data
let jsonName: String? = nil    // Username is null
let jsonAge: Int? = 28
let jsonEmail: String? = nil   // Email is null
// Using it directly — won't compile
let displayName = "Name: " + jsonName  // Compilation error!

لا يمكن استخدام الأنواع الاختيارية مباشرة. لم يتم تجميع كود Alice. جربت فك التغليف القسري بع��امة تعجب، وتعطل البرنامج فورًا:

SWIFT
// Forced unwrap — runtime crash
let displayName = "Name: \(jsonName!)"  // ❌ fatal error

(2) الحل: فك التغليف الآمن

تحولت Alice إلى if-let لفك التغليف الآمن، وعمل الكود باستقرار على الفور:

SWIFT
var userName = "Unknown"
var userAge = 0
var userEmail = "Not provided"
if let name = jsonName {
    userName = name
}
if let age = jsonAge {
    userAge = age
}
if let email = jsonEmail {
    userEmail = email
}
print("Name: \(userName), Age: \(userAge), Email: \(userEmail)")

المخرجات:

TEXT 📖 للعرض فقط
Name: Unknown, Age: 28, Email: Not provided

لا فك تغليف قسري، لا أعطال. تم التعامل مع القيم nil بأمان مع القيم الافتراضية.

(3) النتيجة: انخفض معدل الأعطال بشكل كبير

البُعد قبل (فك التغليف القسري) بعد (if-let)
أعطال القيم الفارغة 3-5 أسبوعيًا 0
وقت التصحيح 1-2 ساعة لكل مشكلة لا حاجة للتصحيح
قابلية قراءة الكود علامات تعجب في كل مكان فك تغليف آمن وواضح
تأث��ر المستخدم أعطال عرضية تدهور سلس

3. الصفوف (Tuples)

يجمع الصف قيمًا متعددة في قيمة مركبة واحدة. يمكن أن تكون قيم الصف من أنواع مختلفة، مما يجعلها مثالية لتنظيم البيانات المؤقتة.

100%
graph TB
    A[الصف] --> B["(Int, String, Bool)"]
    A --> C[تركيبات أنواع متعددة]
    B --> D["الوصول: بالفهرس"]
    B --> E["الوصول: .0 .1 .2"]
    B --> F["التفكيك: let (a, b)"]
    C --> G["إرجاع قيم متعددة"]
    C --> H["حاوية بيانات مؤقتة"]
الميزة الصف البنية/الفئة
التعريف (Int, String) يتطلب تعريف نوع منفصل
قابلية القراءة جيدة للبيانات المؤقتة البسيطة أفضل للبيانات التجارية المعقدة
الأداء مخصص في المكدس، خفيف الوزن المكدس/الكومة حسب النوع
حالة الاستخدام إرجاع متعدد للدوال، تجميع مؤقت الكائنات المعقدة، نماذج البيانات

(1) إنشاء الصفوف وأنواعها

غلف قيمًا متعددة بين قوسين، مفصولة بفواصل:

SWIFT
// Unlabeled tuple
let httpStatus = (404, "Not Found")
print(httpStatus.0)  // 404
print(httpStatus.1)  // "Not Found"
// Labeled tuple (recommended)
let user = (name: "Alice", age: 28, isActive: true)
print(user.name)      // Alice
print(user.age)       // 28
print(user.isActive)  // true

(2) الوصول إلى عناصر الصف

ثلاث طرق للوصول إلى العناصر:

SWIFT
let product = (id: 1001, name: "MacBook Pro", price: 1999.99)
// Method 1: By index
print(product.0)   // 1001
print(product.1)   // MacBook Pro
// Method 2: By label
print(product.id)    // 1001
print(product.name)  // MacBook Pro
// Method 3: Destructuring
let (id, name, price) = product
print("\(id): \(name) - $\(price)")

▶ مثال: بيانات استجابة API

SWIFT
// ============================================
// Simulate API responses returning user and order data
// Demonstrates tuple creation, labels, and destructuring
// ============================================
// Simulate fetching a user profile summary
let userSummary = (id: 1001, name: "Alice Johnson", age: 28, country: "US")
print("User: \(userSummary.name) (ID: \(userSummary.id))")
print("Age: \(userSummary.age), Country: \(userSummary.country)")
// Simulate fetching order statistics
let orderStats = (totalOrders: 15, totalSpent: 3450.0, lastOrderDate: "2026-07-15")
// Destructure the tuple
let (orderCount, totalSpent, lastDate) = orderStats
print("Orders: \(orderCount), Total: $\(totalSpent), Last: \(lastDate)")
// Tuple as a function return value
func getCoordinates() -> (Double, Double) {
    return (40.7128, -74.0060)
}
let (lat, lng) = getCoordinates()
print("Location: \(lat), \(lng)")

المخرجات:

TEXT 📖 للعرض فقط
User: Alice Johnson (ID: 1001)
Age: 28, Country: US
Orders: 15, Total: $3450.0, Last: 2026-07-15
Location: 40.7128, -74.0060

4. الاختياريات (Optionals)

Optional هي واحدة من أهم ميزات الأمان في Swift. تشير صراحة إلى أن القيمة قد تكون موجودة (لها قيمة) أو غير موجودة (nil)، مما يحل مشكلة العطل بسبب القيم الفارغة بشكل أساسي.

100%
graph TB
    A[Optional] --> B["لها قيمة: .some(value)"]
    A --> C["لا قيمة: .none (nil)"]
    B --> D["String? = \"مرحبًا\""]
    C --> E["String? = nil"]
    D --> F["يجب فك التغليف قبل الاستخدام"]
    E --> G["تشير إلى عدم وجود القيمة"]
النوع يسمح بـ nil مثال
String يجب أن تكون لها قيمة
String? ✅ يمكن أن تكون nil nil أو "مرحبًا"
Int يجب أن تكون لها قيمة
Int? ✅ يمكن أن تكون nil nil أو 42

(1) التصريح بالاختياريات

أضف ? بعد النوع للتصريح بنوع اختياري:

SWIFT
var middleName: String? = nil     // Initially nil
var age: Int? = 28                // Has a value
var email: String? = "alice@example.com"  // Has a value
// Assign nil
middleName = "Marie"  // Now has a value
middleName = nil      // Back to no value
// Optional is fundamentally an enum
let name: Optional<String> = "Alice"  // Full syntax
let name2: String? = "Alice"          // Shorthand (recommended)

(2) معنى nil

nil تعني "لا قيمة"، وليس "القيمة هي 0 أو سلسلة فارغة":

SWIFT
let notSet: Int? = nil    // Not set
let zero: Int = 0         // Value is 0 (not nil)
let empty: String? = ""   // Has a value, an empty string (not nil)
// Check for nil
if notSet == nil {
    print("Value is not set")
}
💡 نصيحة: ميّز بين "القيمة فارغة" و "القيمة هي nil". السلسلة الفارغة "" هي قيمة String صالحة، بينما nil تعني أن القيمة غير موجودة على الإطلاق.

▶ مثال: الاستعلام عن معلومات المستخدم

SWIFT
// ============================================
// Simulate querying user info from a database
// Demonstrates Optional declaration and nil checking
// ============================================
// Simulated query results (some fields may be empty)
var dbUserName: String? = "Alice Johnson"
var dbUserAge: Int? = 28
var dbUserEmail: String? = nil  // Email is null in database
var dbUserPhone: String? = nil  // Phone not provided
// Output each field using nil checks
print("=== User Profile ===")
print("Name: \(dbUserName ?? "Unknown")")
if dbUserAge != nil {
    print("Age: \(dbUserAge!)")  // Confirmed has value, safe to force-unwrap
} else {
    print("Age: Not provided")
}
if dbUserEmail == nil {
    print("Email: Not provided")
}
if dbUserPhone == nil {
    print("Phone: Not provided")
}

المخرجات:

TEXT 📖 للعرض فقط
=== User Profile ===
Name: Alice Johnson
Age: 28
Email: Not provided
Phone: Not provided

5. فك التغليف الآمن

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

(1) فك التغليف بـ if-let

if-let هي طريقة فك التغليف الآمن الأكثر شيوعًا: إذا كانت القيمة موجودة، ادخل فرع if واربطها بثابت جديد؛ وإلا ادخل فرع else:

SWIFT
let optionalName: String? = "Alice"
if let name = optionalName {
    print("Hello, \(name)")  // name is String, not Optional
} else {
    print("Name is nil")
}
// Unwrap multiple optionals at once
let a: Int? = 10
let b: Int? = 20
if let x = a, let y = b {
    print("Sum: \(x + y)")  // 30
} else {
    print("One or both values are nil")
}
// Add conditions
if let x = a, x > 5 {
    print("\(x) is greater than 5")  // 10 > 5
}
طريقة فك التغليف الصياغة آمنة متى تستخدم
فك تغليف قسري value! ❌ يتعطل إذا كان nil متأكد 100% من وجود قيمة
if-let if let v = value ✅ آمنة تحتاج منطق تفرع
guard-let guard let v = value ✅ آمنة تحتاج خروج مبكر
دمج nil value ?? default ✅ آمنة توفير قيمة افتراضية

(2) فك التغليف بـ guard-let

تستخدم guard-let نمط "الخروج المبكر": إذا كانت القيمة nil، نفذ فرع else واخرج من النطاق الحالي:

SWIFT
func processUser(name: String?, age: Int?) {
    guard let validName = name else {
        print("Name is required")
        return
    }
    guard let validAge = age, validAge >= 18 else {
        print("Must be at least 18")
        return
    }
    print("Processing: \(validName), age \(validAge)")
}
processUser(name: "Alice", age: 28)  // Processing: Alice, age 28
processUser(name: nil, age: 20)      // Name is required
processUser(name: "Bob", age: 15)    // Must be at least 18

(3) متى تستخدم فك التغليف القسري

يستخدم فك التغليف القسري اللاحقة ! ويجب استخدامه فقط عندما تكون متأكدًا تمامًا من وجود القيمة:

SWIFT
// ✅ Reasonable use case
let optionalNumber: Int? = 42
if optionalNumber != nil {
    // Already checked, safe to force-unwrap
    print("Number is \(optionalNumber!)")
}
// ❌ Dangerous: crashes if nil
let badNumber: Int? = nil
// print(badNumber!)  // fatal error

▶ مثال: قراءة التكوين بأمان

SWIFT
// ============================================
// Read app configuration, demonstrating three unwrapping methods
// ============================================
import Foundation
// Simulate reading a config file (some keys may be missing)
let configTimeout: Int? = 30
let configRetry: Int? = nil         // Missing retry config
let configAPIKey: String? = "abc-123-def"
let configEnv: String? = nil        // Missing environment config
// 1. if-let for safe access
if let timeout = configTimeout {
    print("Timeout: \(timeout) seconds")
}
// 2. guard-let for early exit
func validateConfig() {
    guard let apiKey = configAPIKey else {
        print("Error: API Key is missing")
        return
    }
    print("API Key: \(apiKey.prefix(3))...")
}
validateConfig()
// 3. Nil-coalescing operator provides defaults
let retryCount = configRetry ?? 3
let envName = configEnv ?? "development"
print("Retry: \(retryCount) times")
print("Environment: \(envName)")
// 4. if-let with combined conditions
if let timeout = configTimeout, timeout > 0 {
    print("Valid timeout: \(timeout)s")
} else {
    print("Invalid or missing timeout")
}

المخرجات:

TEXT 📖 للعرض فقط
Timeout: 30 seconds
API Key: abc...
Retry: 3 times
Environment: development
Valid timeout: 30s

6. مثال كامل: التحقق من صحة نموذج تسجيل المستخدم

SWIFT
// ============================================
// User registration form validation
// Combines tuples for data bundling + Optional for safe unwrapping
// ============================================
import Foundation
// 1. Simulate form input (may be empty)
let inputName: String? = "Alice Johnson"
let inputEmail: String? = "alice@example.com"
let inputAge: String? = "28"
let inputPhone: String? = nil  // Phone is optional
// 2. Use tuple to return multiple validation results
func validateRegistration(name: String?, email: String?, age: String?) -> (isValid: Bool, message: String) {
    guard let name = name, name.count >= 2 else {
        return (false, "Name must be at least 2 characters")
    }
    guard let email = email, email.contains("@") else {
        return (false, "Invalid email address")
    }
    guard let ageStr = age, let ageInt = Int(ageStr), ageInt >= 18 else {
        return (false, "Must be at least 18 years old")
    }
    return (true, "Registration successful!")
}
// 3. Run validation
let result = validateRegistration(name: inputName, email: inputEmail, age: inputAge)
if result.isValid {
    print("Status: \(result.message)")
    // 4. Safely unwrap and use the data
    if let name = inputName, let email = inputEmail {
        let welcome = "Welcome \(name)! Confirmation sent to \(email)"
        print(welcome)
    }
    // 5. Nil-coalescing operator for optional info
    let phoneInfo = inputPhone ?? "Not provided"
    print("Phone: \(phoneInfo)")
} else {
    print("Error: \(result.message)")
}

المخرج��ت:

TEXT 📖 للعرض فقط
Status: Registration successful!
Welcome Alice Johnson! Confirmation sent to alice@example.com
Phone: Not provided

❓ أسئلة شائعة

س ما الفرق بين الصف والمصفوفة؟
ج يمكن للصفوف احتواء أنواع مختلفة ولها طول ثابت، مثالية لتجميعات البيانات المؤقتة الصغيرة. يجب أن تكون المصفوفات متجانسة، ذات طول متغير، ومناسبة للمجموعات الكبيرة من نفس نوع البيانات.
س ما هو Optional بشكل أساسي؟
ج Optional هو تعداد: .some(value) تعني وجود قيمة، .none تعني nil. String? هي أساسًا سكر صياغي لـ Optional<String>.
س كيف أختار بين عامل دمج nil ?? وif-let؟
ج استخدم ?? عندما يكون لديك قيمة افتراضية (سطر واحد). استخدم if-let عندما تحتاج منطق تفرع. استخدم guard-let عندما تحتاج الخروج المبكر.
س ما هي الاختيارية المفكوكة ضمنيًا بـ !؟
ج String! هي اختيارية مفكوكة ضمنيًا، مصرح عنها بـ ! بدلاً من ?. لا تحتاج لفك تغليفها يدويًا، لكنها ستتعطل إذا كانت nil. تستخدم بشكل رئيسي للتوافق مع Objective-C.
س هل يمكنني فك تغليف قيم متعددة وإضافة شروط في if-let واحد؟
ج نعم. if let x = a, let y = b, x > y { } يفك تغليف كل من a وb، ويتطلب أيضًا x > y. يجب استيفاء جميع الشروط لدخول كتلة if.

📖 ملخص


📝 تمارين

  1. مبتدئ: أنشئ صفًا لتخزين معلومات المنتج (ID، الاسم، السعر). الوصول إلى كل حقل بالتسمية وأخرجه.
  2. متوسط: اكتب دالة findUser(id: Int) -> (name: String?, age: Int?) تحاكي الاستعلام عن مستخدم بـ ID. أعد قيمًا صالحة لمستخدم موجود وnil لمستخدم مفقود. استخدم if-let لفك التغليف الآمن وإخراج النتائج.
  3. متقدم: اكتب برنامج تحقق من صحة نموذج تسجيل الدخول. اقبل اسم المستخدم (String?) وكلمة المرور (String?) والعمر (String?). استخدم guard-let للتحقق من أن كل حقل غير nil ويستوفي الشروط (اسم المستخدم > 3 أحرف، كلمة المرور > 6 أحرف، العمر >= 18). أعد صفًا يحتوي على (isValid, errorMessage).
Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%