مبادئ SOLID في Swift: النظرية والتطبيق لتطوير iOS

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا تعتبر مبادئ SOLID مهمة لمطور Swift

كل مطور iOS يواجه عاجلاً أم آجلاً مشكلة "كود السباغيتي": وحدات التحكم تتضخم إلى آلاف الأسطر، تغيير كيان واحد يكسر ثلاثة آخرين، ويصبح الاختبار كابوساً. مبادئ SOLID هي خمس قواعد أساسية للتصميم الشيئي تساعد في إنشاء كود مرن وقابل للصيانة والاختبار بلغة Swift.

في هذه المقالة، سنشرح كل مبدأ من مبادئ SOLID بأمثلة محددة من تطوير iOS. ستتعلم كيفية تطبيق هذه المبادئ في المشاريع الحقيقية، وتجنب الأخطاء الشائعة. ستكون المادة مفيدة لمطوري Junior وكذلك للمتخصصين ذوي الخبرة الذين يرغبون في تنظيم معرفتهم.

1. Single Responsibility Principle (SRP) — مبدأ المسؤولية الواحدة

الجوهر: يجب أن يكون لكل class سبب واحد فقط للتغيير. بمعنى آخر، يجب أن يكون class مسؤولاً عن مهمة واحدة فقط.

المشكلة: ViewController "الإلهي"

الخطأ النموذجي هو وضع كل المنطق في UIViewController. لنلق نظرة على مثال سيء:

class UserProfileViewController: UIViewController {
    @IBOutlet weak var nameLabel: UILabel!
    
    func loadUser() {
        // 1. منطق الشبكة
        let url = URL(string: "https://api.example.com/user")!
        URLSession.shared.dataTask(with: url) { data, _, _ in
            // 2. تحليل JSON
            let user = try! JSONDecoder().decode(User.self, from: data!)
            // 3. الحفظ في Core Data
            self.saveToCoreData(user)
            // 4. تحديث واجهة المستخدم
            DispatchQueue.main.async {
                self.nameLabel.text = user.name
            }
        }.resume()
    }
    
    private func saveToCoreData(_ user: User) { /* ... */ }
}

الحل: فصل المسؤوليات

سنقسم الكود إلى مكونات منفصلة:

// 1. خدمة للعمل مع الشبكة
class UserNetworkService {
    func fetchUser(completion: @escaping (Result<User, Error>) -> Void) {
        let url = URL(string: "https://api.example.com/user")!
        URLSession.shared.dataTask(with: url) { data, _, error in
            if let data = data {
                do {
                    let user = try JSONDecoder().decode(User.self, from: data)
                    completion(.success(user))
                } catch {
                    completion(.failure(error))
                }
            } else if let error = error {
                completion(.failure(error))
            }
        }.resume()
    }
}

// 2. مدير تخزين البيانات
class UserStorageManager {
    func save(_ user: User) {
        // منطق الحفظ في Core Data / Realm
    }
}

// 3. ViewModel (أو Presenter)
class UserViewModel {
    private let networkService = UserNetworkService()
    private let storageManager = UserStorageManager()
    
    var onUserUpdated: ((User) -> Void)?
    
    func loadUser() {
        networkService.fetchUser { [weak self] result in
            switch result {
            case .success(let user):
                self?.storageManager.save(user)
                self?.onUserUpdated?(user)
            case .failure(let error):
                print(error.localizedDescription)
            }
        }
    }
}

// 4. ViewController الآن يدير واجهة المستخدم فقط
class UserProfileViewController: UIViewController {
    @IBOutlet weak var nameLabel: UILabel!
    private let viewModel = UserViewModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel.onUserUpdated = { [weak self] user in
            DispatchQueue.main.async {
                self?.nameLabel.text = user.name
            }
        }
        viewModel.loadUser()
    }
}

النتيجة: كل class لديه سبب واحد للتغيير. اختبار وصيانة هذا الكود أصبحت أسهل بكثير.

المدونات

توصيات الكتب