مكتبة لإدارة التبعية مستوحاة من "بيئة" سويفتوي.
تم تحفيز هذه المكتبة وتصميمها على مدار العديد من الحلقات على خالية من النقاط ، وهي سلسلة فيديو تستكشف البرمجة الوظيفية واللغة السريعة ، التي يستضيفها براندون ويليامز وستيفن سيليس.
التبعيات هي الأنواع والوظائف في تطبيقك والتي تحتاج إلى التفاعل مع الأنظمة الخارجية التي لا تتحكم فيها. الأمثلة الكلاسيكية على ذلك هي عملاء API الذين يقدمون طلبات الشبكة إلى الخوادم ، ولكن أيضًا على ما يبدو أشياء غير ضارة مثل UUID
ومبتكرات Date
والوصول إلى الملفات والأعداد الافتراضية للمستخدم وحتى الساعات والوقتات ، يمكن اعتبارها جميعها تبعيات.
يمكنك أن تصل إلى حد كبير في تطوير التطبيقات دون التفكير في إدارة التبعية (أو ، كما يحب البعض أن يسميها ، "حقن التبعية") ، ولكن في نهاية المطاف يمكن أن تسبب التبعيات غير الخاضعة للرقابة العديد من المشكلات في قاعدة الكود ودورة التطوير الخاصة بك:
تجعل التبعيات غير المنضبط من الصعب كتابة اختبارات حتمية سريعة لأنك عرضة للتقلبات في العالم الخارجي ، مثل أنظمة الملفات ، واتصال الشبكة ، وسرعة الإنترنت ، ووقت تشغيل الخادم ، والمزيد.
لا تعمل العديد من التبعيات بشكل جيد في معاينات Swiftui ، مثل مديري المواقع والتعرف على الكلام ، وبعضها لا يعمل حتى في أجهزة المحاكاة ، مثل مديري الحركة ، وأكثر من ذلك. هذا يمنعك من أن تكون قادرًا على التكرار بسهولة على تصميم الميزات إذا استفادت من هذه الأطر.
تميل التبعيات التي تتفاعل مع الطرف الثالث ، والمكتبات غير Apple (مثل Firebase ، ومكتبات مقبس الويب ، ومكتبات الشبكات ، وما إلى ذلك) إلى أن تكون ثقيلة الوزن وتستغرق وقتًا طويلاً للتجميع . هذا يمكن أن يتباطأ دورة التطوير الخاصة بك.
لهذه الأسباب ، وأكثر من ذلك بكثير ، يتم تشجيعك بشدة على السيطرة على تبعياتك بدلاً من السماح لهم بالسيطرة عليك.
ولكن ، السيطرة على التبعية ليست سوى البداية. بمجرد التحكم في تبعياتك ، تواجه مجموعة كاملة من المشكلات الجديدة:
كيف يمكنك نشر التبعيات خلال تطبيقك بالكامل بطريقة أكثر مريحة من تمريرها بشكل صريح في كل مكان ، ولكن أكثر أمانًا من الحصول على تبعية عالمية؟
كيف يمكنك تجاوز التبعيات لجزء واحد فقط من طلبك؟ يمكن أن يكون هذا مفيدًا لتجاوز التبعيات للاختبارات والمعاينات Swiftui ، بالإضافة إلى تدفقات المستخدم المحددة مثل تجارب Onboarding.
كيف يمكنك أن تتأكد من تجاوز جميع التبعيات التي تستخدمها الميزة في الاختبارات؟ سيكون من غير الصحيح أن يختبر الاختبار بعض التبعيات ولكن يترك الآخرين يتفاعلون مع العالم الخارجي.
تتناول هذه المكتبة جميع النقاط المذكورة أعلاه ، وأكثر من ذلك بكثير .
تتيح لك المكتبة تسجيل تبعياتك الخاصة ، ولكنها تأتي أيضًا مع العديد من التبعيات التي يمكن التحكم فيها خارج المربع (انظر DependencyValues
للحصول على قائمة كاملة) ، وهناك فرصة جيدة يمكنك الاستفادة من واحدة على الفور. إذا كنت تستخدم Date()
أو UUID()
أو Task.sleep
أو الجمع بين المجمولين مباشرة في منطق الميزة الخاصة بك ، فيمكنك بالفعل البدء في استخدام هذه المكتبة.
@ Observable
final class FeatureModel {
var items : [ Item ] = [ ]
@ ObservationIgnored
@ Dependency ( . continuousClock ) var clock // Controllable way to sleep a task
@ ObservationIgnored
@ Dependency ( . date . now ) var now // Controllable way to ask for current date
@ ObservationIgnored
@ Dependency ( . mainQueue ) var mainQueue // Controllable scheduling on main queue
@ ObservationIgnored
@ Dependency ( . uuid ) var uuid // Controllable UUID creation
// ...
}
بمجرد إعلان تبعياتك ، بدلاً من التواصل مع Date()
، UUID()
، وما إلى ذلك ، يمكنك استخدام التبعية المعرفة على نموذج الميزات الخاص بك:
@ Observable
final class FeatureModel {
// ...
func addButtonTapped ( ) async throws {
try await clock . sleep ( for : . seconds ( 1 ) ) // ? Don't use 'Task.sleep'
items . append (
Item (
id : uuid ( ) , // ? Don't use 'UUID()'
name : " " ,
createdAt : now // ? Don't use 'Date()'
)
)
}
}
هذا هو كل ما يتطلبه الأمر لبدء استخدام التبعيات التي يمكن التحكم فيها في ميزاتك. مع هذا القليل من العمل المقدم الذي تم إنجازه ، يمكنك البدء في الاستفادة من صلاحيات المكتبة.
على سبيل المثال ، يمكنك بسهولة التحكم في هذه التبعيات في الاختبارات. إذا كنت ترغب في اختبار المنطق داخل طريقة addButtonTapped
، فيمكنك استخدام دالة withDependencies
لتجاوز أي تبعيات لنطاق اختبار واحد. إنه سهل مثل 1-2-3:
@ Test
func add ( ) async throws {
let model = withDependencies {
// 1️⃣ Override any dependencies that your feature uses.
$0 . clock = . immediate
$0 . date . now = Date ( timeIntervalSinceReferenceDate : 1234567890 )
$0 . uuid = . incrementing
} operation : {
// 2️⃣ Construct the feature's model
FeatureModel ( )
}
// 3️⃣ The model now executes in a controlled environment of dependencies,
// and so we can make assertions against its behavior.
try await model . addButtonTapped ( )
#expect (
model . items == [
Item (
id : UUID ( uuidString : " 00000000-0000-0000-0000-000000000000 " ) ! ,
name : " " ,
createdAt : Date ( timeIntervalSinceReferenceDate : 1234567890 )
)
]
)
}
هنا نتحكم هنا في تبعية date
لإرجاع دائمًا في نفس التاريخ ، ونحن نتحكم في تبعية uuid
لإرجاع UUID المتمثل في التلقائي في كل مرة يتم فيها التذرع بها ، وحتى نتحكم في تبعية clock
باستخدام ImmediateClock
للاسكواش طوال الوقت في واحد فوري. إذا لم نتحكم في هذه التبعيات ، فسيكون هذا الاختبار صعبًا للغاية لأنه لا توجد طريقة للتنبؤ بدقة بما سيتم إرجاعه حسب Date()
و UUID()
، وعلينا أن ننتظر وقتًا حقيقيًا في العالم لتمريره ، جعل الاختبار بطيئا.
لكن التبعيات التي يمكن التحكم فيها ليست مفيدة فقط للاختبارات. يمكن استخدامها أيضًا في معاينات Xcode. لنفترض أن الميزة أعلاه تستخدم ساعة للنوم لفترة من الوقت قبل حدوث شيء ما في العرض. إذا كنت لا ترغب في الانتظار حرفيًا حتى يتم تمرير الوقت لمعرفة كيفية تغيير العرض ، فيمكنك تجاوز التبعية على مدار الساعة لتكون ساعة "فورية" باستخدام سمة .dependencies
.
#Preview (
traits : . dependencies {
$0 . continuousClock = . immediate
}
) {
// All access of '@Dependency(.continuousClock)' in this preview will
// use an immediate clock.
FeatureView ( model : FeatureModel ( ) )
}
سيجعل ذلك بحيث تستخدم المعاينة ساعة فورية عند التشغيل ، ولكن عند التشغيل في جهاز محاكاة أو على الجهاز ، فإنها ستظل تستخدم ContinuousClock
مباشرًا. هذا يجعل من الممكن تجاوز التبعيات فقط للمعاينات دون التأثير على كيفية تشغيل تطبيقك في الإنتاج.
هذه هي الأساسيات للبدء في استخدام المكتبة ، ولكن لا يزال هناك الكثير مما يمكنك القيام به. يمكنك معرفة المزيد بتعمق عن المكتبة من خلال استكشاف الوثائق والمقالات:
بداية سريعة (مثل المعلومات أعلاه) : تعلم أساسيات البدء مع المكتبة قبل الغوص في جميع ميزاتها.
ما هي التبعيات؟ : تعرف على التبعيات ، وكيف تعقد الكود الخاص بك ، ولماذا تريد التحكم فيها.
باستخدام التبعيات : تعلم كيفية استخدام التبعيات المسجلة في المكتبة.
تسجيل التبعيات : تعلم كيفية تسجيل تبعياتك مع المكتبة حتى تصبح متاحة على الفور من أي جزء من قاعدة الكود الخاصة بك.
التبعيات المباشرة والمعاينة والاختبار : تعلم كيفية توفير تطبيقات مختلفة لتبعياتك لاستخدامها في التطبيق المباشر ، وكذلك في معاينات XCode ، وحتى في الاختبارات.
الاختبار : أحد الأسباب الرئيسية للتحكم في التبعيات هو السماح باختبار أسهل. تعلم بعض النصائح والحيل لكتابة اختبارات أفضل مع المكتبة.
تصميم التبعيات : تعلم تقنيات حول تصميم تبعياتك بحيث تكون أكثر مرونة للحقن في الميزات والتجاوز للاختبارات.
التبعيات المتجددة : تعلم كيف يمكن تغيير التبعيات في وقت التشغيل حتى تتمكن أجزاء معينة من التطبيق من استخدام تبعيات مختلفة.
عمر الاعتماد : تعرف على عمر التبعيات ، وكيفية إطالة عمر التبعية ، وكيف يتم توريث التبعيات.
أنظمة نقطة الدخول الفردية : تعرف على أنظمة "نقطة الدخول الفردية" ، ولماذا تكون الأنسب لمكتبة التبعيات هذه ، على الرغم من أنه من الممكن استخدام المكتبة مع أنظمة نقاط الدخول غير المنقولة.
قمنا بإعادة بناء تطبيق Scrumdinger التجريبي الخاص بـ Apple باستخدام أفضل الممارسات الحديثة لتطوير Swiftui ، بما في ذلك استخدام هذه المكتبة للتحكم في التبعيات في الوصول إلى نظام الملفات وآبار واجهات برمجة تطبيقات التعرف على الكلام. يمكن العثور على هذا العرض التوضيحي هنا.
أحدث وثائق لواجهة برمجة تطبيقات التبعيات متاحة هنا.
يمكنك إضافة تبعيات إلى مشروع XCode عن طريق إضافته إلى مشروعك كحزمة.
https://github.com/pointfreeco/swift-dependencies
إذا كنت ترغب في استخدام التبعيات في مشروع SwiftPM ، فسيكون ذلك بسيطًا مثل إضافته إلى Package.swift
الخاصة بك.
dependencies: [
. package ( url : " https://github.com/pointfreeco/swift-dependencies " , from : " 1.0.0 " )
]
ثم إضافة المنتج إلى أي هدف يحتاج إلى الوصول إلى المكتبة:
. product ( name : " Dependencies " , package : " swift-dependencies " ) ,
إذا كنت ترغب في مناقشة هذه المكتبة أو لديك سؤال حول كيفية استخدامها لحل مشكلة معينة ، فهناك عدد من الأماكن التي يمكنك مناقشتها مع عشاق زملائه الخاليين من النقاط:
تتحكم هذه المكتبة في عدد من التبعيات خارج المربع ، ولكنها مفتوحة أيضًا للتمديد. جميع المشاريع التالية تبني على قمة التبعيات:
هناك العديد من مكتبات حقن التبعية الأخرى في المجتمع السريع. لكل منها مجموعة من الأولويات والمقايضات التي تختلف عن التبعيات. فيما يلي بعض الأمثلة المعروفة:
يتم إصدار هذه المكتبة تحت رخصة معهد ماساتشوستس للتكنولوجيا. انظر الترخيص للحصول على التفاصيل.