كل ما تحتاجه هو URL

صورة

يتبادل مستخدمو فكونتاكتي 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

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


All Articles