هذه المقالة هي استمرار للمقال
التفاعل مع الخادم من خلال واجهة برمجة تطبيقات في iOS على Swift 3. الجزء 1 وتحديث
مقالة قديمة مكتوبة في Objective-C على swift 3.
نظرية موجزة
الحصول على طلب
GET هو أبسط طريقة لطلب HTTP ، وهو ما يستخدمه المتصفح لتحميل صفحات الويب. يتم استخدامه لطلب المحتوى الموجود على عنوان URL معين. قد يكون المحتوى ، على سبيل المثال ، صفحة ويب أو صورة أو ملف صوتي. حسب الاصطلاح ، تكون طلبات GET للقراءة فقط ، ووفقًا لمعيار W3C ، لا يجب استخدامها في العمليات التي تغير جانب الخادم. على سبيل المثال ، لن نستخدم طلب GET لإرسال نموذج أو إرسال صورة ، لأن هذه العمليات تتطلب بعض التغييرات على جانب الخادم (سنستخدم POST في هذه الحالات).
طلب ما بعد
يرسل POST البيانات لمزيد من المعالجة إلى عنوان URL. يتم تضمين المعلمات في نص الطلب باستخدام نفس تنسيق GET. على سبيل المثال ، إذا أردنا نشر نموذج يحتوي على حقلين ، اسم وعمر ، فسوف نرسل شيئًا مشابهًا للاسم = Martin & age = 29 في نص الطلب.
يتم استخدام هذه الطريقة لإرسال المعلمات على نطاق واسع في صفحات الويب. الحالات الأكثر شعبية هي الأشكال. عندما نملأ النموذج على الموقع وننقر على إرسال ، من المرجح أن يكون الطلب POST.
في تطبيقنا ، نستخدم POST لترتيب النكات. سنرسل الأصوات (أو +1 أو -1) إلى الخادم البعيد.
يمكن بناء بيانات طلب POST باستخدام تنسيقات مختلفة. عادةً ما يتم تنسيق المعلمات وفقًا لمعايير ترميز عنوان URL (وفقًا لمعيار W3C HTML). هذا هو التنسيق الافتراضي ويستخدم على نطاق واسع في العديد من المتصفحات. تقبل طريقتنا قاموس القاموس كوسيطة ، ولكن لا يمكننا إرسال قاموس القاموس عبر اتصال HTTP لأنه من نوع Swift الداخلي. لإعادة التوجيه عبر اتصال HTTP ، نحتاج إلى إنشاء تمثيل يمكن التعرف عليه من القاموس. إنه مثل التواصل مع أجنبي. نترجم رسالتنا إلى لغة عالمية ، وهي تترجم من لغة عالمية إلى لغتها الأم. اللغة العالمية في HTTP هي معيار W3C ، ولغتنا هي Swift ، ولغة المستلم غير معروفة لنا.
يحدد معيار W3C القواعد التي تحدد معنى تمثيل معترف به لكل حالة. في حالتنا ، نحتاج إلى تقديم المعلمات التالية للجزء المشفر من url- النموذج من المعيار (على سبيل المثال ، param1 = var1 & param2 = var2).
عرض الويب
باستخدام أدوات لغة البرمجة ، يمكننا إرسال الطلبات إلى خادم بعيد. هذا ما تفعله المتصفحات قبل عرض صفحة الويب. الفرق فقط في محتوى الجواب. يتم تنسيق صفحات الويب باستخدام معيار HTML ، الذي يحدد مجموعة من القواعد لكيفية تعريف علامات ترميز مختلفة بشكل رسومي. تبدو هذه القواعد بسيطة ، ولكن عرض صفحة كاملة باتباع معيار W3C يعد مهمة صعبة. لحسن الحظ ، يحتوي iOS على مكون UIWebView مضمن يستخدم محرك WebKit المعروف ويفسر HTML / CSS / JavaScript ويعرض صفحات الويب بالكامل داخل UIView.
هناك العديد من الحالات التي نريد فيها التحكم في تدفق التنقل. على سبيل المثال ، نريد أن نعرف متى يتم تحميل محتوى معين أو عنوان URL معين.
أو ربما نقوم بتطبيق متصفح آمن للأطفال ، نريد منع المستخدم من تحميل الصفحات التي تندرج تحت معايير معينة ، مثل الجنس أو المخدرات. لجميع أنواع التخصيص هذه ، نقوم بإنشاء مثيل لفئة تطبق بروتوكول UIWebViewDelegate كمفوض UIWebView. يمكننا تنفيذ الطرق التالية:
webView:shouldStartLoadWithRequest:navigationType: webViewDidStartLoad: webViewDidFinishLoad: webView:didFailLoadWithError:
باستخدام الطريقة الأولى ، يمكننا التحكم في تدفق التنقل من خلال السماح بطلبات معينة أو حظرها. الطرق الثلاث الأخرى هي الأحداث الإعلامية (تعطي أسماء الطرق فكرة جيدة عن الحدث).
تنفيذ التصويت عبر طلب POST
سنقوم بإضافة
ملفات MainViewController.swift و
HTTPCommunication.swift ، وإنشاء ملف
WebViewController.swift جديد
نحدد فيه webView.
أولاً ، قم بإنشاء ملف WebViewController.swift جديد وقم بتعريف فئة WebViewController فيه:
WebViewController.swift import UIKit class WebViewController: UIViewController { } extension WebViewController { }
ننفذ الآن وظيفة إجراء طلبات POST في الفئة المسؤولة عن جميع عمليات HTTP الخاصة بنا: فئة HTTPCommunication. للقيام بذلك ، قم بإضافة طريقة postURL جديدة (_: params: finishHandler :) في HTTPCommunication.swift ، وهي مشابهة لطريقة استرداد URL السابقة (_: finishHandler :).
HTTPCommunication.swift class HTTPCommunication: NSObject { … func retrieveURL(_ url: URL, completionHandler: @escaping ((Data) -> Void)) { … }
كود الطريقة
func postURL(_ url: URL, params: [String: Int], completionHandler: @escaping ((Data) -> Void)) { // (K.1) self.completionHandler = completionHandler // (K.2) func postBody(params: [String: Int]) -> Data? { // (K.3) var paramsArr: [String] = [] for (key, value) in params { paramsArr.append("\(key)=\(value)") } let postBodyString: String = paramsArr.joined(separator: "&") let postBodyData: Data? = postBodyString.data(using: .utf8) return postBodyData } var request: URLRequest = URLRequest(url: url) // (K.4) request.httpMethod = "POST" request.httpBody = postBody(params: params) let session: URLSession = URLSession(configuration: .default, delegate: self, delegateQueue: nil) // (K.5) let task: URLSessionDownloadTask = session.downloadTask(with: request) task.resume() }
(K.1) مع الإغلاق ، سنعمل خارج هذه الوظيفة ، وبالتالي فإننا نشير إليها بواسطةescaping.
(K.2) نقوم بتخزين الإغلاق الممر في خاصية finishHandler.
(K.3) نكتب طريقة تحول قاموس المعلمات التي تم تمريرها إلى شكل سلسلة ، ثم ترميز هذه السلسلة إلى نوع البيانات في ترميز utf8.
(K.4) نقوم بإنشاء طلب باستخدام عنوان URL الذي تم تمريره وتكوينه: قم بتعيين POST كطريقة ، وقم بعمل معلماتنا لنوع البيانات باستخدام utf8 كنص الطلب.
(K.5) أخيرًا ، قم بإنشاء جلسة بتكوين افتراضي ومفوض مثلنا. وننشئ مهمة لتحميل نتيجة هذا الطلب في التخزين المؤقت. في النهاية ، تذويب المهمة.
الآن دعنا نضيف الواجهة الضرورية إلى MainViewController.swift. أضف زرين للتصويت والتصويت up و downDown ، مما سيؤدي على التوالي إلى زيادة أو تقليل تصنيف النكتة الحالية. كما نضيف زر "Chuck Who؟" ، والذي سنقوم بملئه بالوظيفة في القسم الخاص بعرض الويب.
في MainViewController.swift ، قم بإدراج رمز التهيئة للتصويت UPButton و votDownButton و chuckWhoButton.
MainViewController.swift lazy var jokeLabel: UILabel! = … var jokeID: Int! lazy var activityView: UIActivityIndicatorView! = …
رمز تهيئة الزر
lazy var voteUpButton: UIButton! = { // (L.1) let button: UIButton = UIButton(type: .system) // (L.2) button.setTitle("Vote Up", for: .normal) button.sizeToFit() button.addTarget(self, action: #selector(self.voteUp), for: .touchUpInside) // (L.3) self.view.addSubview(button) // (L.4) return button // (L.5) }() lazy var voteDownButton: UIButton! = { let button: UIButton = UIButton(type: .system) button.setTitle("Vote Down", for: .normal) button.sizeToFit() button.addTarget(self, action: #selector(self.voteDown), for: .touchUpInside) self.view.addSubview(button) return button }() lazy var chuckWhoButton: UIButton! = { let button: UIButton = UIButton(type: .system) button.setTitle("Chuck Who?", for: .normal) button.sizeToFit() button.addTarget(self, action: #selector(self.chuckWho), for: .touchUpInside) self.view.addSubview(button) return button }()
رمز التهيئة لجميع الأزرار الثلاثة هو نفسه.
(L.1) نعلن متغير كسول ونهيئه بإغلاق.
(L.2) داخل الإغلاق ، نحدد متغيرًا محليًا للزر ، ونوع النظام ، ونحدد الاسم والحجم.
(L.3) نربط الزر مع الإجراء المقابل عند الضغط عليه.
(L.4) إضافة إلى التسلسل الهرمي للرؤية.
(L.5) ونخصص هذا المتغير المحلي لمتغيرنا الكسول.
بعد ذلك ، في MainViewController.swift ، أدخل رمز الطريقة للأزرار
MainViewController.swift class MainViewController: UIViewController { … func retrieveRandomJokes() { … }
رمز الطريقة للأزرار
func voteUp() { let http: HTTPCommunication = HTTPCommunication() // (M.1) let params: [String: Int] = ["joke_id": self.jokeID, "vote": 1] // (M.2) if let url = URL(string: "http://example.com/rater/vote") { // (M.3) http.postURL(url, params: params) { (data) in // (M.4) print("\(data). Voted Up") } } } func voteDown() { let http: HTTPCommunication = HTTPCommunication() let params: [String: Int] = ["joke_id": self.jokeID, "vote": -1] if let url = URL(string: "http://example.com/rater/vote") { http.postURL(url, params: params) { (data) in print("\(data). Voted Down") } } } func chuckWho() { }
رمز طرق التصويت صعودا وهبوطا هو نفسه.
(M.1) إنشاء كائن فئة للاتصال بالخادم.
(M.2) ننشئ قاموسًا للمعلمات يتضمن معرف النكتة التي نصوت لها ، والقيمة الفعلية للتصويت هي +1 أو -1.
(M.3) بعد ذلك ، نحصل على عنوان url بأمان من شريط العنوان لنطاق التدريب
http://example.com/rater/vote.
(M.4) ونرسل عبر POST طلبًا للحصول على معلمات URL الخاصة بنا. وطبع على وحدة التحكم خطًا يشير إلى اكتمال الطلب.
بعد ذلك ، في MainViewController.swift نعيد كتابة كود طريقة configStackView ، مع مراعاة التغييرات التي تم إجراؤها على واجهة المستخدم.
MainViewController.swift func configStackView() -> UIStackView { let innerStackView: UIStackView = UIStackView(arrangedSubviews: [self.voteUpButton, self.voteDownButton]) // (N.1) innerStackView.axis = .horizontal // (N.2) innerStackView.distribution = .fillEqually let mainStackView: UIStackView = UIStackView(arrangedSubviews: [self.jokeLabel, innerStackView, self.chuckWhoButton]) // (N.3) mainStackView.spacing = 50 // (N.4) mainStackView.axis = .vertical mainStackView.distribution = .fillEqually self.view.addSubview(mainStackView) // (N.5) return mainStackView }
(N.1) إنشاء عارض داخلي StackView يحتوي على زرين للتصويت.
(N.2) نكشف المحور الرأسي ؛ التوزيع هو نفسه.
(رقم 3) في mainStackView الرئيسي ، أضف innerStackView والزر الخاص بـ Chuck Norris إلى الملصق من الجزء الأخير.
(رقم 4) تكوين mainStackView.
(رقم 5) إضافة mainStackView إلى العرض الهرمي.
نطلق تطبيقنا ونرى الواجهة كما في الشكل. 1
الشكل 1 واجهة تطبيقنا مع أزرار إضافية للتصويتنتحقق من أنه عند التصويت على نكتة أو ضدها ، يتم عرض الرسائل التالية في وحدة التحكم:
345 bytes. Voted Up
أو
345 bytes. Voted Down
الذي يشير إلى طلب POST مكتمل بنجاح إلى الخادم.
كتبنا تطبيق نكتة باستخدام فعل icndb API و GET HTTP. تمكنا من إظهار هذه النكات على UIView ويمكن تقدير كل نكتة. ترسل هذه الإجراءات طلب POST إلى الخادم البعيد ، والذي يجب أن يحفظ تقديرنا.
استخدام webViews لعرض صفحات الويب
سنقوم بإضافة WebView لعرض صفحة ويكيبيديا حول Chuck Norris. يتم الخلط بينها بلمسة زر واحدة.
في ملف WebViewController.swift ، اكتب كعب الوظيفة التالي:
WebViewController.swift import UIKit class WebViewController: UIViewController { lazy var webView: UIWebView = { // (O.1) self.configWebView() }() lazy var toolbar: UIToolbar = { // (O.2) self.configToolbar() }() override func viewDidLoad() { super.viewDidLoad() } func back() { // (O.3) self.webView.goBack() } func forward() { self.webView.goForward() } } extension WebViewController { func configWebView() -> UIWebView { // (O.4) } func configToolbar() -> UIToolbar { // (O.5) } func configConstraints() { // (O.6) } }
(O.1) نقوم بإنشاء متغيرات كسولة لـ webView
(O.2) وشريط الأدوات.
(O.3) نقوم بإنشاء طرق ذهابًا وإيابًا ، للتنقل في تاريخ زيارة الروابط.
(O.4) نضيف طرق تهيئة webView إلى الامتداد
(O.5) وشريط الأدوات
(O.6) والقيود على الواجهة.
نرسم الآن رمز كل وظيفة:
func configWebView() -> UIWebView { let webView: UIWebView = UIWebView()
(P.1) نقوم بتهيئة webView وإضافة العرض إلى التسلسل الهرمي.
func configToolbar() -> UIToolbar { let toolbar: UIToolbar = UIToolbar(frame: CGRect.zero) // (Q.1) let backButton: UIBarButtonItem = UIBarButtonItem(title: , style: .plain, target: self, action: #selector(self.back)) // (Q.2) let forwardButton: UIBarButtonItem = UIBarButtonItem(title: , style: .plain, target: self, action: #selector(self.forward)) toolbar.setItems([backButton, forwardButton], animated: false) // (Q.3) toolbar.backgroundColor = UIColor.lightGray // (Q.4) self.view.addSubview(toolbar) return toolbar }
(س 1) إنشاء شريط أدوات بإطار صفر.
(س 2) نقوم بإنشاء زرين للتنقل في تاريخ زيارة الروابط. مع الأسماء "<" و ">" والإجراءات المرفقة بالطريقة المقابلة في webView.
(س 3) أضف هذه الأزرار إلى شريط الأدوات.
(س 4) تعيين لون الخلفية ، مثل شريط التنقل ، رمادي فاتح. وإضافة العرض إلى التسلسل الهرمي.
func configConstraints() { self.webView.translatesAutoresizingMaskIntoConstraints = false // (R.1) NSLayoutConstraint.activate([ // (R.2) self.webView.topAnchor.constraint(equalTo: self.topLayoutGuide.topAnchor), self.webView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), self.webView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), self.webView.bottomAnchor.constraint(equalTo: self.toolbar.topAnchor) ]) self.toolbar.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ // (R.3) self.toolbar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), self.toolbar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), self.toolbar.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), self.toolbar.heightAnchor.constraint(equalToConstant: 44.0) ]) }
(R.1) تعطيل أقنعة الاستعادة التلقائية بحيث لا تتعارض مع قيودنا
(R.2) بالنسبة إلى webView ، قم بتهيئة الجوانب الأربعة للعرض.
(R.3) بالنسبة لشريط الأدوات ، قم بتكوين ثلاثة جوانب من العرض ، باستثناء الجزء العلوي ، ولكن بالإضافة إلى ذلك ، قم بتعيين الارتفاع إلى الحجم القياسي 44.0.
وأعد كتابة كود ViewDidLoad () كما يلي:
override func viewDidLoad() { super.viewDidLoad() self.configConstraints()
(S.1) استدعاء وضع القيود.
(S.2) احصل على عنوان url بأمان من شريط العنوان لصفحة ويكيبيديا
en.wikipedia.org/wiki/Chuck_Norris(S.3) نقوم بإنشاء طلب من url.
(S.4) وننفذ الطلب المقدم في webView.
نعود إلى MainViewController ونملأه بطريقة استدعاء المعلومات حول Chuck Norris.
MainViewController.swift func chuckWho() { self.navigationController?.show(WebViewController(), sender: self)
(T.1) عند النقر فوق هذا الزر في حزمة navigationController ، ضع نسخة جديدة من webView.
التين. يوضح 2 كيف يبدو webView في تطبيقنا.
التين. 2. العرض النهائي ل webView قمنا بتنفيذها