Class هو نوع مرجعي (reference type) في لغة Swift، يتم تمرير نسخه بالمرجع وليس بالنسخ عند التعيين. على عكس الهياكل، تدعم الفئات الوراثة وإلغاء التهيئة والعد التلقائي للمراجع ARC لإدارة الذاكرة. وفقًا لـ Swift Programming Language Guide, 2026، class ضروري للعمل مع أطر UI الخاصة بـ Apple (UIKit, AppKit) وتنفيذ الأنماط التي تتطلب هوية مشتركة للكائن. الاختيار بين class و struct هو أحد القرارات المعمارية الرئيسية في Swift.
النقاط الرئيسية
Class — نوع مرجعي مركب في Swift يجمع الخصائص والطرق في كيان واحد مع دعم الوراثة والإرسال الديناميكي. على عكس struct، يتم إنشاء نسخة الفئة في heap، ويخزن المتغير مرجعًا لهذه النسخة، وليس البيانات نفسها.
عند تعيين متغير فئة لمتغير آخر، يشير كلاهما إلى نفس الكائن في الذاكرة. التغييرات من خلال مرجع واحد تكون مرئية من خلال الآخر — هذه خاصية أساسية لأنواع المراجع، تُستخدم في أنماط التفويض والمراقبة والحالة المشتركة.
وفقًا لـ توثيق Apple Swift، الفئات هي الطريقة الوحيدة للعمل مع UIKit و AppKit، حيث ترث جميع مكونات UI من UIView و UIViewController. بالإضافة إلى ذلك، الفئات ضرورية لتنفيذ الأنماط التي تتطلب هوية الكائن (مرجعين لكائن واحد) ودورة حياة محكومة.
دلالات النوع المرجعي — الخاصية الرئيسية للفئات. عند تعيين فئة لمتغير جديد، ينسخ Swift المرجع، وليس البيانات. جميع المتغيرات التي تشير إلى نفس النسخة ترى حالتها الحالية ويمكنها تعديلها. يختلف هذا السلوك جوهريًا عن أنواع القيم، حيث يحصل كل متغير على نسخة مستقلة.
// مثال على دلالات النوع المرجعي
class User {
var name: String
init(name: String) { self.name = name }
}
let user1 = User(name: "Alice")
let user2 = user1 // user2 — نفس المرجع
user2.name = "Bob"
print(user1.name) // "Bob" — تم تغييره عبر user2!
// التحقق من الهوية باستخدام العامل ===
print(user1 === user2) // true — نفس الكائن
العاملان === (الهوية) و !== يتحققان مما إذا كان متغيران يشيران إلى نفس نسخة الفئة. هذا يختلف عن == (المساواة)، الذي يقارن قيم الخصائص. العامل === غير متاح لـ struct — أنواع القيم ليس لديها هوية.
الوراثة — آلية يمكن للفئة من خلالها تبني خصائص وطرق الفئة الأم. في Swift، يمكن للفئة أن ترث فقط من أب واحد (وراثة مفردة)، ولكن يمكنها تنفيذ بروتوكولات متعددة. الكلمة الأساسية override تسمح بتجاوز طريقة أو خاصية موروثة.
أي فئة لا ترث من فئة أخرى تصبح تلقائيًا أساسية (لا تخلط مع NSObject). تحدد الفئة الفرعية الأب بنقطتين بعد اسمها. إذا تجاوزت الفئة الفرعية طريقة الأب، يجب عليها استدعاء super.method() للحفاظ على سلوك الأب — هذا مطلب من المترجم.
الكلمة الأساسية final قبل class تمنع الوراثة. يمكن للمترجم تحسين استدعاءات طرق الفئة النهائية من خلال الإرسال الثابت، مما يحسن الأداء. استخدم final للفئات غير المخصصة للتوسيع — هذا يوثق نيتك ويسرع الكود.
// مثال على وراثة الفئات في Swift
class Vehicle {
var speed: Double = 0
func description() -> String {
"Speed: \(speed) km/h"
}
}
// Car ترث من Vehicle
class Car: Vehicle {
var brand: String = "Unknown"
override func description() -> String {
"\(brand) - \(speed) km/h"
}
}
// فئة نهائية — تمنع الوراثة
final class ElectricCar: Car {
var batteryLevel: Double = 100
}
let tesla = ElectricCar()
tesla.brand = "Tesla"
tesla.speed = 120
print(tesla.description()) // "Tesla - 120.0 km/h"
الوراثة آلية قوية ولكنها مسؤولة. التسلسلات الهرمية العميقة (أكثر من 5 مستويات) تعقد الصيانة والاختبار. لإعادة الاستخدام الوظيفي دون وراثة، استخدم البروتوكولات مع extension والبرمجة الموجهة بالبروتوكول — نهج تروجه Apple كبديل للتسلسلات الهرمية العميقة للفئات.
يستخدم Swift ARC (العد التلقائي للمراجع) لإدارة ذاكرة الفئات. كل نسخة فئة لها عداد مراجع قوية. عند إنشاء مرجع قوي جديد، يزيد العداد؛ عند تدميره، يقل. عندما يصل العداد إلى الصفر، يتم تحرير الذاكرة.
Deinit — طريقة تُستدعى تلقائيًا قبل تحرير نسخة الفئة. تحرر الموارد: تغلق الملفات، تلغي الاشتراكات في الإشعارات، توقف المؤقتات. Deinit متاح فقط للفئات — الهياكل والتعدادات لا تملكه.
لمنع دورات المراجع القوية (retain cycles)، يوفر Swift مراجع weak و unowned. weak هو مرجع اختياري يصبح تلقائيًا nil عند تحرير الكائن. unowned غير اختياري ولكنه يشير إلى كائن مضمون العيش أطول من السياق الحالي. دورة الاحتفاظ النموذجية تحدث في علاقة أب-ابن: الابن يحتفظ بمرجع قوي للأب.
// مثال على ARC والمرجع الضعيف
class Parent {
var name: String
var child: Child?
init(name: String) { self.name = name }
deinit { print("\(name) تم تحريره") }
}
class Child {
var name: String
weak var parent: Parent? // weak يمنع دورة الاحتفاظ
init(name: String) { self.name = name }
deinit { print("\(name) تم تحريره") }
}
var parent: Parent? = Parent(name: "Anna")
parent?.child = Child(name: "Mia")
parent?.child?.parent = parent
parent = nil // كلا الكائنين تم تحريرهما!
// بدون weak سيؤدي إلى دورة احتفاظ
استخدم دائمًا weak للمراجع من كائن ابن إلى الأب ولقوائم الالتقاط في closures. استخدم unowned فقط عندما تكون متأكدًا أن الكائن سيعيش أطول من السياق الحالي — الاستخدام غير الصحيح لـ unowned يمكن أن يسبب تعطلًا عند الوصول إلى ذاكرة محررة.
الاختيار بين class و struct هو قرار معماري يؤثر على الأداء وأمان الخيوط وتصميم API. انظر جدول الفروق الرئيسية لاتخاذ القرار الصحيح في كل حالة.
| الخاصية | class | struct |
|---|---|---|
| النوع | نوع مرجعي | نوع قيمي (نسخة) |
| الذاكرة | Heap + ARC | Stack / مضمّن |
| الوراثة | يدعم (أب واحد) | لا يدعم |
| Deinit | متاح | غير متاح |
| الهوية (===) | يدعم | لا يدعم |
| Mutating | غير مطلوب (دائمًا mutating) | فقط مع mutating |
| Init memberwise | لا يُنشأ | يُنشأ تلقائيًا |
| أمان الخيوط | غير مضمون (حالة مشتركة) | مضمون (نسخ) |
استخدم الفئات عندما تحتاج هوية مشتركة (أجزاء متعددة من الكود تعمل مع كائن واحد)، وراثة، أو تفاعل مع Objective-C runtime. لكل شيء آخر، الهياكل هي المفضلة — أسرع وأكثر أمانًا في الكود متعدد الخيوط ولا تتطلب إدارة ذاكرة.
على الرغم من توصية Apple باستخدام struct افتراضيًا، الفئات ضرورية في عدة سيناريوهات محددة. دعنا نفحص كل منها بأمثلة عملية.
جميع مكونات UI في iOS و macOS هي فئات ترث من UIView (iOS) أو NSView (macOS). لا يمكنك استبدال UIViewController بـ struct — يتطلب وراثة و deinit لتحرير الموارد. عند العمل مع UIKit، استخدم الفئات للمتحكمات والعروض والمفوضين.
نمط Singleton (نسخة فئة واحدة للتطبيق بأكمله) يتطلب دلالات مرجعية. المديرون: NetworkManager، SettingsManager، AnalyticsService — عادةً ما يُنفذون كفئات بخاصية static مشتركة. الهياكل غير مناسبة لأن كل نسخة ستكون مستقلة.
عندما يجب أن يكون الكائن مصدر الحقيقة الوحيد ويُمرر بين الوحدات بالمرجع — استخدم class. هذا ينطبق على إدارة الحالة، حيث تغيير كائن في مكان واحد يجب أن يكون مرئيًا في جميع المكونات التابعة. لـ ObservableObject في SwiftUI، الفئات إلزامية.
// ObservableObject — class مطلوب لـ SwiftUI
import SwiftUI
class AppViewModel: ObservableObject {
@Published var isLoggedIn: Bool = false
@Published var username: String = ""
func login(user: String) {
isLoggedIn = true
username = user
}
}
// الاستخدام في عرض SwiftUI
struct ContentView: View {
@StateObject var viewModel = AppViewModel()
var body: some View {
Text(viewModel.isLoggedIn ? "مرحبًا" : "تسجيل الدخول")
}
}
القاعدة: إذا كان يجب أن يكون للكائن هوية (مرجعين -> كائن واحد)، أو نسخة واحدة، أو يعمل مع UIKit/Objective-C — اختر class. إذا كان الكائن يحتوي ببساطة على بيانات — اختر struct.
الأسئلة الشائعة
Class هو نوع مرجعي في Swift يدعم الوراثة وإلغاء التهيئة و ARC لإدارة الذاكرة. تُخزن نسخ الفئات في heap، وتحتوي المتغيرات على مرجع للكائن وليس نسخة منه.
Class — نوع مرجعي (يُمرر بالمرجع)، يدعم الوراثة و deinit. Struct — نوع قيمي (يُنسخ)، لا يدعم الوراثة، لكنه ينفذ البروتوكولات ويحصل على init memberwise تلقائيًا. يوصي Swift باستخدام struct كنوع افتراضي.
ARC (العد التلقائي للمراجع) — آلية إدارة ذاكرة لفئات Swift. لكل نسخة عداد مراجع قوية. عندما يصل العداد إلى الصفر، تُحرر الذاكرة. المراجع weak و unowned تمنع دورات الاحتفاظ بين الكائنات.
Deinit — طريقة فئة تُستدعى تلقائيًا قبل تحرير ذاكرتها. تُستخدم لإغلاق الملفات وإلغاء الاشتراكات في الإشعارات وعمليات التنظيف الأخرى. Deinit متاح فقط للفئات — الهياكل لا تملكه.
استخدم class لمكونات UI في UIKit/AppKit و singleton و ObservableObject في SwiftUI والكائنات ذات الهوية المشتركة (delegate, observer) وعند العمل مع Objective-C runtime. لنماذج البيانات و DTO والتكوينات، يفضل استخدام struct.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.