المقدمة: لماذا الأداء مهم من اليوم الأول
عندما تبدأ الكتابة بلغة Swift، من السهل التركيز فقط على الوظائف: "المهم أن يعمل". لكن المطورين ذوي الخبرة يعرفون: تحسين الأداء ليس لمسة نهائية، بل هو أساس يُبنى من أول سطور الكود. التطبيق البطيء يفقد المستخدمين، ويستنزف البطارية، ويحصل على تقييمات سيئة.
في هذه المقالة، سنحلل الجوانب الرئيسية لتحسين تطبيقات Swift لنظامي iOS وmacOS. ستتعلم كيفية تجنب الأخطاء الشائعة للمبتدئين، وستتعلم العمل مع الذاكرة، والخيوط، والتنميط. كل قسم يحتوي على أمثلة عملية للكود يمكنك تطبيقها فوراً في مشاريعك.
1. إدارة الذاكرة: ARC وتجنب دورات الاحتفاظ (retain cycles)
تستخدم Swift Automatic Reference Counting (ARC) لإدارة الذاكرة. هذا يعني أن الكائنات يتم تحريرها عندما لا يكون هناك مراجع قوية لها. لكن إذا قمت بإنشاء مرجع دائري (retain cycle)، فلن يتم تحرير الذاكرة أبداً - سيحدث تسرب.
المراجع الضعيفة وغير المملوكة
استخدم weak و unowned لكسر الدورات. غالباً ما يكون هذا ضرورياً في الإغلاقات (closures) والمفوضين (delegates).
class ViewController: UIViewController { var networkManager: NetworkManager? func fetchData() { networkManager?.fetch { [weak self] result in guard let self = self else { return } // معالجة النتيجة self.updateUI(with: result) } }}متى تستخدم:
weak— إذا كان المرجع يمكن أن يصبحnil(مثل المفوض).unowned— إذا كنت متأكداً أن الكائن سيعيش أطول من الإغلاق (مثل وحدة التحكم الأم).
تجنب النسخ غير الضرورية
أنواع القيم (Value types) مثل الهياكل والتعدادات تُنسخ عند التعيين. للبيانات الكبيرة، استخدم class أو قم بالتمرير بالمرجع عبر inout.
// سيء: نسخ مصفوفة كبيرةfunc processLargeArray(_ array: [Int]) { // array — نسخة}
// جيد: تمرير بالمرجعfunc processLargeArray(_ array: inout [Int]) { // array — مرجع إلى الأصل}2. العمل مع تعدد الخيوط: GCD و async/await
iOS وmacOS أنظمة متعددة الخيوط. إذا قمت بتنفيذ عمليات ثقيلة (تحميل بيانات، معالجة صور) على الخيط الرئيسي، ستتجمد الواجهة. استخدم Grand Central Dispatch (GCD) أو async/await الحديث.
GCD: الأنماط الأساسية
DispatchQueue.global(qos: .userInitiated).async { // عمل ثقيل في الخلفية let result = performHeavyCalculation() DispatchQueue.main.async { // تحديث واجهة المستخدم على الخيط الرئيسي self.label.text = "\\(result)" }}QoS (Quality of Service):
.userInteractive— لواجهة المستخدم (فوري تقريباً)..userInitiated— لإجراءات المستخدم (ثوانٍ)..utility— للمهام الطويلة (أشرطة التقدم)..background— للمزامنة الخلفية (غير عاجل).
Async/await (Swift 5.5+)
طريقة أكثر قابلية للقراءة للعمل مع التزامن:
func fetchImage(from url: URL) async throws -> UIImage { let (data, _) = try await URLSession.shared.data(from: url) guard let image = UIImage(data: data) else { throw URLError(.badServerResponse) } return image}
// الاستدعاء في TaskTask { do { let image = try await fetchImage(from: url) self.imageView.image = image } catch { print("خطأ في التحميل: \\(er