يتبادل مستخدمو فكونتاكتي 10 مليارات رسالة يوميًا. يرسلون كل الصور الأخرى ، كاريكاتير ، الميمات والمرفقات الأخرى.
URLProtocol
كيف توصلنا إلى تطبيق iOS لتحميل الصور باستخدام
URLProtocol
،
URLProtocol
خطوة بخطوة على كيفية تنفيذ تطبيقنا.
منذ عام ونصف تقريبًا ، كان تطوير قسم الرسائل الجديد في تطبيق VK لنظام iOS على قدم وساق. هذا هو القسم الأول المكتوب بالكامل في سويفت. وهو موجود في وحدة منفصلة
vkm
(رسائل VK) ، والتي لا تعرف أي شيء عن جهاز التطبيق الرئيسي. يمكن تشغيله في مشروع منفصل - ستظل الوظيفة الأساسية لقراءة الرسائل وإرسالها تعمل. في التطبيق الرئيسي ، تتم إضافة وحدات التحكم في الرسائل عبر وحدة التحكم في عرض الحاوية المقابلة لعرضها ، على سبيل المثال ، قائمة بالمحادثات أو الرسائل في محادثة.
تُعد الرسائل أحد أكثر الأقسام شيوعًا في تطبيق VKontakte للأجهزة المحمولة ، لذلك من المهم أن تعمل مثل الساعة. في مشروع
messages
، نقاتل من أجل كل سطر من التعليمات البرمجية. لقد أحببنا دائمًا مدى دقة الرسائل في التطبيق ، ونحن نسعى جاهدين لضمان بقاء كل شيء كما هو.
مع ملء القسم تدريجيا بوظائف جديدة ، تعاملنا مع المهمة التالية: كان علينا التأكد من أن الصورة المرفقة بالرسالة قد تم عرضها لأول مرة في مسودة ، وبعد إرسالها ، في القائمة العامة للرسائل. يمكننا فقط إضافة وحدة نمطية للعمل مع
PHImageManager
، ولكن الظروف الإضافية جعلت المهمة أكثر صعوبة.
عند اختيار لقطة ، يمكن للمستخدم معالجتها: تطبيق مرشح ، تدوير ، اقتصاص ، إلخ. في تطبيق VK ، يتم تنفيذ هذه الوظيفة في مكون
AssetService
منفصل. الآن كان من الضروري أن نتعلم العمل معه من مشروع الرسالة.
حسنًا ، المهمة بسيطة جدًا ، سنفعلها. هذا هو الحل المتوسط تقريبًا ، لأن هناك الكثير من الاختلافات. نأخذ البروتوكول ونفريغه في الرسائل ونبدأ في ملؤه بالطرق. نضيف إلى AssetService ، تكييف البروتوكول وإضافة تطبيق التخزين المؤقت لدينا! لالزوجة. ثم نضع التطبيق في رسائل ، ونضيفه إلى بعض الخدمات أو المدير الذي سيعمل مع كل هذا ، والبدء في استخدامه. في الوقت نفسه ، لا يزال هناك مطور جديد ، وفي الوقت الذي يحاول فيه معرفة كل شيء ، فإنه يدين بتهمس ... (حسنًا ، أنت تفهم). في الوقت نفسه ، يظهر العرق على جبينه.
هذا القرار لم
يكن يرضينا تظهر كيانات جديدة تحتاج مكونات الرسائل إلى معرفتها عند العمل مع الصور من
AssetService
. يحتاج المطور أيضًا إلى القيام بعمل إضافي لمعرفة كيفية عمل هذا النظام. أخيرًا ، كان هناك رابط ضمني إضافي لمكونات المشروع الرئيسي ، والذي نحاول تجنبه حتى يستمر قسم الرسائل في العمل كوحدة نمطية مستقلة.
أردت حل المشكلة حتى لا يعرف المشروع أي شيء على الإطلاق عن نوع الصورة التي تم اختيارها ، وكيفية تخزينها ، وما إذا كان يحتاج إلى تحميل وعرض خاصين. علاوة على ذلك ، لدينا بالفعل القدرة على تنزيل الصور التقليدية من الإنترنت ، فقط لا يتم تنزيلها من خلال خدمة إضافية ، ولكن ببساطة عن طريق
URL
. وفي الواقع ، لا يوجد فرق بين هذين النوعين من الصور. يتم تخزين بعضها فقط محليا ، بينما يتم تخزين البعض الآخر على الخادم.
لذا توصلنا إلى فكرة بسيطة للغاية: ماذا لو كان بالإمكان تعلم الأصول المحلية للتحميل عبر
URL
؟ يبدو أنه بنقرة واحدة من أصابع
Thanos ، فإنه سيحل جميع مشاكلنا: لست بحاجة إلى معرفة أي شيء عن
AssetService
، وإضافة أنواع جديدة من البيانات وزيادة
AssetService
دون جدوى ، وتعلم كيفية تحميل نوع جديد من الصور ، والعناية
AssetService
البيانات
AssetService
. يبدو وكأنه خطة.
كل ما نحتاج إليه هو عنوان URL
نظرنا في هذه الفكرة وقررنا تحديد تنسيق
URL
الذي سنستخدمه لتحميل الأصول المحلية:
asset://?id=123&width=1920&height=1280
سنستخدم قيمة خاصية
localIdentifier
لـ
localIdentifier
،
localIdentifier
معلمات
width
height
لتحميل الصور بالحجم المطلوب. نضيف أيضًا بعض المعلمات الأخرى مثل
crop
filter
rotate
، مما سيتيح لك التعامل مع معلومات الصورة التي تمت معالجتها.
للتعامل مع
URL
هذه
URL
سنقوم بإنشاء
AssetURLProtocol
:
class AssetURLProtocol: URLProtocol { }
وتتمثل مهمتها في تحميل الصورة من خلال
AssetService
وإعادة البيانات الجاهزة للاستخدام بالفعل.
كل هذا سيسمح لنا بتفويض عمل بروتوكول
URL Loading System
بالكامل تقريبًا.
داخل الرسائل ، سيكون من الممكن العمل باستخدام
URL
الأكثر شيوعًا ، فقط بتنسيق مختلف. سيكون من الممكن أيضًا إعادة استخدام الآلية الحالية لتحميل الصور ، فمن السهل جدًا إجراء تسلسل في قاعدة البيانات وتنفيذ تخزين البيانات
URLCache
عبر
URLCache
القياسي.
هل نجحت؟ إذا قرأت هذه المقالة ، يمكنك إرفاق صورة من المعرض بالرسالة على تطبيق VKontakte ، ثم نعم :)
لتوضيح كيفية تطبيق
URLProtocol
الخاص بك ، أقترح النظر في هذا مع مثال.
لقد حددنا لأنفسنا المهمة: لتطبيق تطبيق بسيط مع قائمة تحتاج فيها إلى عرض قائمة من لقطات الخريطة عند الإحداثيات المحددة. لتنزيل اللقطات ، سوف نستخدم
MKMapSnapshotter
القياسي من
MapKit
، وسنقوم بتحميل البيانات من خلال
URLProtocol
المخصص. قد تبدو النتيجة مثل هذا:
أولاً ، ننفذ آلية تحميل البيانات بواسطة
URL
. لعرض لقطة الخريطة ، نحتاج إلى معرفة إحداثيات النقطة - خطوط الطول والعرض (
latitude
longitude
). حدد تنسيق
URL
المخصص الذي نريد من خلاله تحميل المعلومات:
map://?latitude=59.935634&longitude=30.325935
الآن ننفذ
URLProtocol
، والذي سيعالج هذه الروابط ويولد النتيجة المرجوة. لنقم بإنشاء فئة
MapURLProtocol
، والتي
URLProtocol
فئة
URLProtocol
الفئة الأساسية. على الرغم من اسمه ،
URLProtocol
هو فئة مجردة ، وإن كان. لا تشعر بالحرج ، نستخدم هنا مفاهيم أخرى - يمثل
URLProtocol
بروتوكول
URL
تمامًا وليس له أي علاقة بمصطلحات OOP. لذا
MapURLProtocol
:
class MapURLProtocol: URLProtocol { }
الآن نعيد تعريف بعض الطرق المطلوبة التي بدونها لن يعمل بروتوكول
URL
:
1. canInit(with:)
override class func canInit(with request: URLRequest) -> Bool { return request.url?.scheme == "map" }
canInit(with:)
طريقة للإشارة إلى أنواع الطلبات التي يمكن لبروتوكول
URL
التعامل معها. على سبيل المثال ، افترض أن البروتوكول سيعالج الطلبات فقط باستخدام مخطط
map
في
URL
. قبل بدء أي طلب ، يمر
URL Loading System
عبر جميع البروتوكولات المسجلة للجلسة ويستدعي هذه الطريقة. سيتم استخدام أول بروتوكول مسجل ، والذي سيعود في هذه الطريقة بشكل
true
، لمعالجة الطلب.
canonicalRequest(for:)
override class func canonicalRequest(for request: URLRequest) -> URLRequest { return request }
المقصود
canonicalRequest(for:)
method هو تقليل الطلب إلى النموذج المتعارف عليه. تقول الوثائق أن تنفيذ البروتوكول نفسه يقرر ما يجب اعتباره تعريفًا لهذا المفهوم. هنا يمكنك تطبيع النظام ، إضافة رؤوس إلى الطلب ، إذا لزم الأمر ، إلخ. والشرط الوحيد لهذه الطريقة للعمل هو أن يكون لكل طلب وارد دائمًا نفس النتيجة ، بما في ذلك لأن هذه الطريقة تستخدم أيضًا للبحث عن الإجابات المخزنة مؤقتًا الطلبات في
URLCache
.
3. startLoading()
تصف طريقة
startLoading()
كل منطق تحميل البيانات الضرورية. في هذا المثال ، تحتاج إلى تحليل
URL
للطلب ، وبناءً على قيم معلمات
latitude
longitude
،
MKMapSnapshotter
إلى
MKMapSnapshotter
وقم بتحميل لقطة الخريطة المطلوبة.
override func startLoading() { guard let url = request.url, let components = URLComponents(url: url, resolvingAgainstBaseURL: false), let queryItems = components.queryItems else { fail(with: .badURL) return } load(with: queryItems) } func load(with queryItems: [URLQueryItem]) { let snapshotter = MKMapSnapshotter(queryItems: queryItems) snapshotter.start( with: DispatchQueue.global(qos: .background), completionHandler: handle ) } func handle(snapshot: MKMapSnapshotter.Snapshot?, error: Error?) { if let snapshot = snapshot, let data = snapshot.image.jpegData(compressionQuality: 1) { complete(with: data) } else if let error = error { fail(with: error) } }
بعد تلقي البيانات ، من الضروري إيقاف تشغيل البروتوكول بشكل صحيح:
func complete(with data: Data) { guard let url = request.url, let client = client else { return } let response = URLResponse( url: url, mimeType: "image/jpeg", expectedContentLength: data.count, textEncodingName: nil ) client.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed) client.urlProtocol(self, didLoad: data) client.urlProtocolDidFinishLoading(self) }
بادئ ذي بدء ، قم بإنشاء كائن من النوع
URLResponse
. يحتوي هذا الكائن على بيانات تعريف مهمة للاستجابة لطلب. ثم نقوم بتنفيذ ثلاث طرق مهمة لكائن من نوع
URLProtocolClient
. تحتوي خاصية
client
من هذا النوع على كل كيان من بروتوكول
URL
. إنه بمثابة وكيل بين بروتوكول
URL
بالكامل
URL Loading System
، والذي ، عند استدعاء هذه الطرق ، يستخلص استنتاجات حول ما يجب القيام به مع البيانات: ذاكرة التخزين المؤقت ، وإرسال الطلبات إلى
completionHandler
، ومعالجة طريقة إيقاف تشغيل البروتوكول بطريقة أو بأخرى ، إلخ. وقد يختلف عدد المكالمات إلى هذه الأساليب اعتمادًا على تطبيق البروتوكول. على سبيل المثال ، يمكننا تنزيل البيانات من الشبكة باستخدام دفعات وإخطار
URLProtocolClient
بشكل دوري بهذا الشأن لإظهار تقدم عملية تحميل البيانات في الواجهة.
في حالة حدوث خطأ في تشغيل البروتوكول ، من الضروري أيضًا معالجة
URLProtocolClient
بهذا بشكل صحيح:
func fail(with error: Error) { client?.urlProtocol(self, didFailWithError: error) }
هذا هو الخطأ الذي سيتم إرساله بعد ذلك إلى
completionHandler
معالجة الطلب ، حيث يمكن معالجته وعرض رسالة جميلة للمستخدم.
4. stopLoading()
يتم
stopLoading()
الأسلوب
stopLoading()
عند اكتمال تشغيل البروتوكول لسبب ما. يمكن أن يكون هذا إما إتمامًا ناجحًا أو إتمام خطأ أو إلغاء طلب. هذا مكان جيد لتحرير الموارد المشغولة أو حذف البيانات المؤقتة.
override func stopLoading() { }
هذا يكمل تنفيذ بروتوكول
URL
، ويمكن استخدامه في أي مكان في التطبيق. لتكون مكان تطبيق بروتوكولنا ، أضف بضعة أشياء أخرى.
URLImageView
class URLImageView: UIImageView { var task: URLSessionDataTask? var taskId: Int? func render(url: URL) { assert(task == nil || task?.taskIdentifier != taskId) let request = URLRequest(url: url) task = session.dataTask(with: request, completionHandler: complete) taskId = task?.taskIdentifier task?.resume() } private func complete(data: Data?, response: URLResponse?, error: Error?) { if self.taskId == task?.taskIdentifier, let data = data, let image = UIImage(data: data) { didLoadRemote(image: image) } } func didLoadRemote(image: UIImage) { DispatchQueue.main.async { self.image = image } } func prepareForReuse() { task?.cancel() taskId = nil image = nil } }
هذه فئة بسيطة ، سليل
UIImageView
، وهو تطبيق مشابه ربما لديك في أي تطبيق. هنا نقوم ببساطة بتحميل الصورة بواسطة
URL
في طريقة
render(url:)
وكتابتها إلى خاصية
image
. الراحة هي أنه يمكنك تحميل أي صورة على الإطلاق ، إما عن طريق
http
/
https
URL
، أو عن طريق
URL
المخصص لدينا.
لتنفيذ طلبات تحميل الصور ، ستحتاج أيضًا إلى كائن من نوع
URLSession
:
let config: URLSessionConfiguration = { let c = URLSessionConfiguration.ephemeral c.protocolClasses = [ MapURLProtocol.self ] return c }() let session = URLSession( configuration: config, delegate: nil, delegateQueue: nil )
تكوين الجلسة مهم بشكل خاص هنا. في
URLSessionConfiguration
هناك خاصية واحدة مهمة بالنسبة لنا -
protocolClasses
. هذه قائمة بأنواع بروتوكولات
URL
التي يمكن لجلسة بهذا التكوين التعامل معها. بشكل افتراضي ، تدعم الجلسة معالجة بروتوكولات
http
/
https
، وإذا كان الدعم المخصص مطلوبًا ، فيجب تحديدها. على سبيل المثال ، حدد
MapURLProtocol
.
كل ما تبقى يجب القيام به هو تطبيق View Controller ، الذي سيعرض لقطات الخريطة. شفرة المصدر يمكن الاطلاع عليها
هنا .
هذه هي النتيجة:
ماذا عن التخزين المؤقت؟
يبدو أن كل شيء يعمل بشكل جيد - باستثناء نقطة واحدة مهمة: عندما ننتقل إلى القائمة ذهابًا وإيابًا ، تظهر بقع بيضاء على الشاشة. يبدو أن اللقطات لا يتم تخزينها في ذاكرة التخزين المؤقت بأي طريقة ولكل استدعاء إلى
render(url:)
method ، نعيد
MKMapSnapshotter
البيانات من خلال
MKMapSnapshotter
. هذا يستغرق وقتا طويلا ، وبالتالي هذه الثغرات في التحميل. يجدر تطبيق آلية تخزين البيانات بحيث لا يتم تنزيل اللقطات التي تم إنشاؤها بالفعل مرة أخرى. نحن هنا نستخدم قوة
URL Loading System
، والذي يحتوي بالفعل على آلية للتخزين المؤقت لـ
URLCache
المتوفرة لهذا الغرض.
النظر في هذه العملية بمزيد من التفصيل وقسم العمل مع ذاكرة التخزين المؤقت إلى مرحلتين مهمتين: القراءة والكتابة.
قراءة
لقراءة البيانات المخزنة مؤقتًا بشكل صحيح ، يحتاج
URL Loading System
إلى مساعدة في الحصول على إجابات للعديد من الأسئلة المهمة:
1. ما URLCache للاستخدام؟بالطبع ، هناك بالفعل
URLCache.shared
، لكن
URL Loading System
لا يمكن استخدامه دائمًا - بعد كل شيء ، قد يرغب المطور في إنشاء واستخدام كيان
URLCache
الخاص به. للإجابة على هذا السؤال ،
URLSessionConfiguration
جلسة
urlCache
خاصية
urlCache
. يتم استخدامه لكل من قراءة وتسجيل الردود على الطلبات. سنقوم
URLCache
بعض
URLCache
لهذه الأغراض في التكوين الحالي لدينا.
let config: URLSessionConfiguration = { let c = URLSessionConfiguration.ephemeral c.urlCache = ImageURLCache.current c.protocolClasses = [ MapURLProtocol.self ] return c }()
2. هل أحتاج إلى استخدام البيانات المخزنة مؤقتًا أو التنزيل مرة أخرى؟تعتمد إجابة هذا السؤال على طلب
URLRequest
الذي نحن بصدد تنفيذه. عند إنشاء طلب ، لدينا الفرصة لتحديد سياسة ذاكرة التخزين المؤقت في وسيطة
cachePolicy
بالإضافة إلى
URL
.
let request = URLRequest( url: url, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 30 )
القيمة الافتراضية هي
.useProtocolCachePolicy
، والتي تتم كتابتها أيضًا في الوثائق. هذا يعني أنه في هذا الإصدار ، تكمن مهمة البحث عن استجابة مخبأة للطلب وتحديد أهميتها بالكامل في تنفيذ بروتوكول
URL
. ولكن هناك طريقة أسهل. إذا قمت بتعيين القيمة
.returnCacheDataElseLoad
، فعند إنشاء الكيان التالي
URL Loading System
URLProtocol
URL Loading System
على بعض العمل: سيطلب من
urlCache
الاستجابة المخزنة مؤقتًا للطلب الحالي باستخدام
cachedResponse(for:)
للأسلوب
cachedResponse(for:)
. إذا كانت هناك بيانات مخزنة مؤقتًا ، فسيتم نقل كائن من النوع
CachedURLResponse
على الفور عند تهيئة
URLProtocol
وتخزينه في خاصية
cachedResponse
:
override init( request: URLRequest, cachedResponse: CachedURLResponse?, client: URLProtocolClient?) { super.init( request: request, cachedResponse: cachedResponse, client: client ) }
CachedURLResponse
هي فئة بسيطة تحتوي على بيانات (
Data
) ومعلومات التعريف الخاصة بها (
URLResponse
).
يمكننا فقط تغيير طريقة
startLoading
والتحقق من قيمة هذه الخاصية بداخلها - وإنهاء البروتوكول على الفور مع هذه البيانات:
override func startLoading() { if let cachedResponse = cachedResponse { complete(with: cachedResponse.data) } else { guard let url = request.url, let components = URLComponents(url: url, resolvingAgainstBaseURL: false), let queryItems = components.queryItems else { fail(with: .badURL) return } load(with: queryItems) } }
سجل
للعثور على البيانات في ذاكرة التخزين المؤقت ، تحتاج إلى وضعها هناك.
URL Loading System
يعتني بهذا العمل. كل ما هو مطلوب منا هو إخبارها أننا نريد تخزين البيانات مؤقتًا عند
cacheStoragePolicy
البروتوكول باستخدام
cacheStoragePolicy
سياسة
cacheStoragePolicy
. هذا هو تعداد بسيط مع القيم التالية:
enum StoragePolicy { case allowed case allowedInMemoryOnly case notAllowed }
تعني أن التخزين المؤقت مسموح به في الذاكرة وعلى القرص ، فقط في الذاكرة أو محظور. في مثالنا ، نشير إلى أن التخزين المؤقت مسموح به في الذاكرة وعلى القرص ، ولماذا لا.
client.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed)
لذلك ، باتباع بعض الخطوات البسيطة ، دعمنا القدرة على تخزين لقطات الخريطة مؤقتًا. والآن يعمل التطبيق مثل هذا:
كما ترون ، لا توجد نقاط بيضاء - يتم تحميل البطاقات مرة واحدة ثم يتم إعادة استخدامها ببساطة من ذاكرة التخزين المؤقت.
ليس دائما سهلا
عند تطبيق بروتوكول
URL
، واجهنا سلسلة من الأعطال.
الأول يتعلق بالتطبيق الداخلي لتفاعل
URL Loading System
مع
URLCache
عند التخزين المؤقت للردود على الطلبات.
تنص الوثائق: على الرغم من سلامة
URLCache
، فإن تشغيل
cachedResponse(for:)
و
storeCachedResponse(_:for:)
طرق القراءة / كتابة الاستجابات للطلبات يمكن أن تؤدي إلى سباق حالات ، وبالتالي ، يجب أن تؤخذ هذه النقطة في الاعتبار في الفئات الفرعية من
URLCache
. توقعنا أن يتم استخدام
URLCache.shared
سيتم حل هذه المشكلة ، لكن تبين أنها خاطئة. لإصلاح ذلك ، نستخدم ذاكرة التخزين المؤقت
ImageURLCache
منفصلة ، وهو سليل
URLCache
، حيث ننفذ الطرق المحددة بشكل متزامن في قائمة انتظار منفصلة. على سبيل المكافأة الممتعة ، يمكننا بشكل منفصل تكوين سعة ذاكرة التخزين المؤقت في الذاكرة وعلى القرص بشكل منفصل عن كيانات
URLCache
الأخرى.
private static let accessQueue = DispatchQueue( label: "image-urlcache-access" ) override func cachedResponse(for request: URLRequest) -> CachedURLResponse? { return ImageURLCache.accessQueue.sync { return super.cachedResponse(for: request) } } override func storeCachedResponse(_ response: CachedURLResponse, for request: URLRequest) { ImageURLCache.accessQueue.sync { super.storeCachedResponse(response, for: request) } }
تم استنساخ مشكلة أخرى فقط على الأجهزة التي تعمل بنظام iOS 9. يمكن تنفيذ طرق بدء تحميل بروتوكول
URL
وإنهائه في سلاسل عمليات مختلفة ، مما قد يؤدي إلى حوادث نادرة ولكنها غير سارة. لحل المشكلة ، نقوم بحفظ الخيط الحالي في طريقة
startLoading
ثم ننفذ كود اكتمال التنزيل مباشرة على هذا الخيط.
var thread: Thread! override func startLoading() { guard let url = request.url, let components = URLComponents(url: url, resolvingAgainstBaseURL: false), let queryItems = components.queryItems else { fail(with: .badURL) return } thread = Thread.current if let cachedResponse = cachedResponse { complete(with: cachedResponse) } else { load(request: request, url: url, queryItems: queryItems) } }
func handle(snapshot: MKMapSnapshotter.Snapshot?, error: Error?) { thread.execute { if let snapshot = snapshot, let data = snapshot.image.jpegData(compressionQuality: 0.7) { self.complete(with: data) } else if let error = error { self.fail(with: error) } } }
متى يمكن أن يكون بروتوكول URL مفيدًا؟
نتيجة لذلك ، يواجه كل مستخدم لتطبيق iOS تقريبًا بطريقة أو بأخرى عناصر تعمل من خلال بروتوكول
URL
. بالإضافة إلى تنزيل الوسائط من المعرض ، فإن التطبيقات المختلفة لبروتوكولات
URL
تساعدنا في عرض الخرائط واستطلاعات الرأي ، فضلاً عن إظهار تجسيدات الدردشة المكونة من صور المشاركين.
مثل أي حل ، يحتوي
URLProtocol
على مزايا وعيوب.
عيوب URLProtocol
- عدم وجود كتابة صارمة - عند إنشاء
URL
يتم تحديد معلمات المخطط والرابط يدويًا من خلال السلاسل. إذا قمت بإجراء خطأ مطبعي ، فلن تتم معالجة المعلمة المطلوبة. هذا يمكن أن يعقد تصحيح التطبيق والبحث عن الأخطاء في تشغيله. في تطبيق VKontakte ، نستخدم URLBuilder
إنشاء URL
الخاصة التي تشكل URL
النهائي بناءً على المعلمات التي تم تمريرها. هذا القرار ليس جميلًا جدًا ويتناقض إلى حد ما مع هدف عدم إنتاج كيانات إضافية ، ولكن لا توجد فكرة أفضل بعد. لكننا نعلم أنه إذا كنت بحاجة إلى إنشاء نوع معين من URL
المخصصة ، فمن المؤكد أن هناك URLBuilder
خاصًا URLBuilder
على عدم ارتكاب خطأ. - الأعطال غير الواضحة - لقد سبق أن وصفت عدة سيناريوهات قد تتسبب في تعطل أحد التطبيقات باستخدام
URLProtocol
. ربما هناك آخرون. لكن يتم حل مثل هذه المشكلات ، كالعادة ، إما عن طريق قراءة أكثر تفكيرًا للوثائق ، أو عن طريق دراسة تتبع المكدس وإيجاد جذر المشكلة بعمق.
فوائد URLProtocol
- ضعف اتصال المكونات - قد لا يعرف جزء التطبيق الذي يبدأ تحميل البيانات التي يحتاجها على الإطلاق كيف يتم تنظيمه: ما هي المكونات المستخدمة لهذا الغرض ، وكيف يتم ترتيب التخزين المؤقت. نحن نعرف فقط عن تنسيق معين
URL
- ونتفاعل معه فقط. - بساطة التنفيذ - من أجل التشغيل الصحيح
URL
للبروتوكول ، يكفي تنفيذ عدة طرق بسيطة وتسجيل البروتوكول. بعد ذلك ، يمكن استخدامه في أي مكان في التطبيق. - — , ,
URL
-. URL
, URLSession
, URLSessionDataTask
. - —
URL
- URL
-, URL Loading System
. - * API — . , API, - ,
URL
-. , API , . URL
- http
/ https
.
URL
- — . . - , - , , , — , . , , —
URL
.
GitHub