رفع قراءة التعليمات البرمجية في تطوير iOS

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

قدمت؟

هل يمكن أن تفهم ما هو الكتاب؟

كيف يمكن أن تجد بسرعة المقطع الذي تهتم به؟

يجب تنظيم الكود الخاص بك ، وكذلك محتويات الكتاب ، بحيث يسهل قراءة الكود وتنقل المعنى فيه.

في هذه المقالة ، سأعرض أمثلة على التعليمات البرمجية المنظمة والتي سيكون للفصول فيها نفس تسلسل الكتل الرئيسية وتفاصيلها.

للراحة ، سأستخدم فئة الكلمة (فئة) ، ولكن ضمني أي نوع من أنواع (فئة ، هيكل ، التعداد).

بفضل تطبيق هذه النصائح ، ستصبح شفرتك قابلة للقراءة ، والتي ستوفر في المستقبل الراحة وسرعة العمل معها.

بالطبع ، يمكن ترقية النصائح الموصوفة حسب رغبتك ، مع مراعاة المبادئ الأساسية.

أولاً ، دعنا نقارن نفس الكود بطريقتين.

مثال على فئة فوضوي:


final class MessyViewController: UIViewController {
private let userService = UserService()
var userID: String?
private var userList: [User]?
@IBOutlet private weak var searchBar: UISearchBar!
weak var delegate: SomeDelegate?
@IBAction private func cancelButtonPressed(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
navigationController?.navigationBar.backgroundColor = .red
navigationItem.title = "Some"
}
@IBOutlet private weak var tableView: UITableView!
}

يشبه هذا الكود تفريغ الأساليب والمتغيرات والمنافذ ، حيث يدمج كل شيء معًا ، يصعب فهم ما يشير إليه وفي أي مكان يجب البحث عنه.

مثال على فئة نقية:


final class CleanViewController: UIViewController {
// MARK: - IBOutlets
@IBOutlet private weak var searchBar: UISearchBar!
@IBOutlet private weak var tableView: UITableView!
// MARK: - Public Properties
var userID: String?
weak var delegate: SomeDelegate?
// MARK: - Private Properties
private let userService = UserService()
private var userList: [User]?
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar()
}
// MARK: - Private Methods
private func setupNavigationBar() {
navigationController?.navigationBar.backgroundColor = .red
navigationItem.title = "Some"
}
// MARK: - IBActions
@IBAction private func cancelButtonPressed(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
}

سطر فارغ 38 - المسافة البادئة لسطر واحد من الطريقة الأخيرة بحيث يمكنك معرفة أين تنتهي شريحة الإغلاق الأخيرة للطريقة وأين تنتهي الفئة.

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

المبادئ الأساسية لتشكيل هيكل طبقي خالص:


  1. استخدم دائمًا // MARK: -
  2. إعطاء أسماء التسميات وتحديد أولوياتها
  3. وضع المنطق خارج طرق دورة الحياة في طرق منفصلة
  4. نحن نستخدم التمديد لتنفيذ البروتوكولات
  5. حدد العناصر المرتبطة منطقيا
  6. نزيل غير المستخدمة
  7. أتمتة الروتين

1. استخدم دائمًا // MARK: -


لسهولة القراءة ، يتم تقسيم الكتاب إلى فصول ، وسيكون أكثر راحة لنا في العمل إذا أنشأنا جدول محتويات فئة باستخدام // MARK: - .

لا تبرز هذه التسمية جيدًا فقط من الشفرة بأكملها ، ولكنها أيضًا تنشئ جدول محتويات تلقائيًا - فهي تسلط الضوء على الأقسام في الشفرة بالخط العريض في قائمة عناصر هذا الملف.


يمكنك عرض جدول محتويات الملف عن طريق النقر فوق الزر بعد السهم الأيمن (>) أعلى الملف بعد اسم هذا الملف أو ctr + 6 (قائمة عناصر المستند).

2. نعطي أسماء التسميات ونؤسس تسلسلها


فيما يلي التصنيفات الرئيسية لتقسيم الرمز إلى كتل متصلة منطقياً وتسلسلها:

// MARK: - IBOutlets
// MARK: - Public Properties
// MARK: - Private Properties
// MARK: - Initializers
// MARK: - Lifecycle
// MARK: - Public Methods
// MARK: - Private Methods
// MARK: - IBActions
view raw MarkList.swift hosted with ❤ by GitHub

عند استخدام طريقة التجميع هذه ، يمكن للمرء التنقل بسهولة في كود أي فئة.

3. سحب المنطق من أساليب دورة الحياة إلى طرق منفصلة


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

NOT Preferred
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.backgroundColor = .red
someButton.layer.cornerRadius = 10
someButton.layer.masksToBounds = true
navigationItem.title = "Some"
print("Some")
}
Preferred
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar()
setupSomeButton()
printSome()
}
// MARK: - Private Methods
private func setupNavigationBar() {
navigationController?.navigationBar.backgroundColor = .red
navigationItem.title = "Some"
}
private func setupSomeButton() {
someButton.layer.cornerRadius = 10
someButton.layer.masksToBounds = true
}
private func printSome() {
print("Some")
}

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

4. استخدام التمديد لتنفيذ البروتوكولات


تأخذ تنفيذ البروتوكول في ملحق ملحوظ // MARK: - SomeProtocol :

NOT Preferred
final class CleanViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// all methods
}
Preferred
final class CleanViewController: UIViewController {
// class stuff here
}
// MARK: - Table View Data Source
extension CleanViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userList?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
return cell
}
}
view raw extension.swift hosted with ❤ by GitHub

ستحتوي هذه التسمية على كل ما يتعلق بهذا البروتوكول - كل ما هو موجود هنا فقط ولا حاجة للذهاب إلى أي مكان آخر ، وإلا ستنتشر أساليب وخصائص البروتوكول في جميع أنحاء الفصل.

5. حدد العناصر المرتبطة منطقيا


لزيادة مستوى الرؤية ، من الضروري تحديد العناصر المرتبطة منطقياً باستخدام سطر فارغ:

NOT Preferred
private func showActivityIndicator(on viewController: UIViewController) {
activityIndicator.center = viewController.view.center
loadingView.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
loadingView.alpha = 0.5
activityIndicator.hidesWhenStopped = true
activityIndicator.style = .whiteLarge
loadingView.center = viewController.view.center
loadingView.clipsToBounds = true
loadingView.layer.cornerRadius = 15
viewController.view.addSubview(loadingView)
viewController.view.addSubview(activityIndicator)
activityIndicator.startAnimating()
}
Preferred
private func showActivityIndicator(on viewController: UIViewController) {
activityIndicator.center = viewController.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.style = .whiteLarge
loadingView.center = viewController.view.center
loadingView.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
loadingView.alpha = 0.5
loadingView.clipsToBounds = true
loadingView.layer.cornerRadius = 15
viewController.view.addSubview(loadingView)
viewController.view.addSubview(activityIndicator)
activityIndicator.startAnimating()
}


6. نزيل غير المستخدمة


لا تترك التعليقات غير الضرورية (افتراضيًا) أو الطرق الفارغة أو الوظائف الناقصة - فهذا يؤدي إلى انسداد الكود. انتبه إلى فئة AppDelegate ، على الأرجح ستجد طرق فارغة هناك مع تعليقات في الداخل.

NOT Preferred
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
//
// func someFunc() {
// print("Some")
// }
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain
//types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits
//the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
Preferred
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
}
view raw AppDelegate.swift hosted with ❤ by GitHub


7. أتمتة الروتينية


لتجنب الكتابة يدويًا في كل فئة // MARK: - SomeMark ، استخدم Code Snippet .


نكتب تسمية ، حددها ، ثم محرر -> إنشاء رمز مقتطف ، ونطلق عليه اسم ونطلق عليه اختصار.

// مارك: - مكافأة


  1. قم بتمييز الفصل الدراسي باستخدام الكلمة الأساسية النهائية إذا لم يكن لهذه الفئة أطفال - يتم تجميع المشروع بشكل أسرع ويتم تشغيل الرمز بشكل أسرع.
  2. قم بتمييز الخصائص والمنافذ والأساليب باستخدام الكلمة الأساسية الخاصة - ستكون متاحة فقط داخل الفصل ولن تكون في قائمة الخصائص والأساليب العامة إذا لم تكن هناك حاجة إليها.


أتمنى لك كل النجاح في تطوير التطبيقات ودع فصلك يصبح أنظف!

// مارك: - مساعدة في كتابة مقال
سيرجي بتشياكوف
أليكسي بليشكوف AlekseyPleshkov

// مارك: - الروابط
راي wenderlich رمز النمط

Source: https://habr.com/ru/post/ar453428/


All Articles