GraphQL iOS: استخدام الوظائف السحابية في تطبيق Swift

في هذه المقالة، أوضحت لك كيفية استخدام GraphQL مع NodeJS Cloud Code في Back4app.

وفي هذا الدليل، أوضحت لك كيفية استخدام عميل Apollo GraphQL iOS مع Swift.

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

هل يبدو ذلك جيدًا؟ لذا احصل على بعض القهوة وانطلق!

قبل البدء…

ستحتاج إلى حساب Back4app مع تطبيق واحد تم إنشاؤه. إذا لم يكن لديك واحدًا بعد، اتبع هذا الدليل وستحصل على كل شيء في وقت قصير.

بعض البرامج التي ستساعدنا…

سنستخدم أيضًا بعض الأشياء لتسريع الأمور.

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

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

سأستخدم Cocoapods لإدارة حزم iOS و NPM لإدارة حزم سطح المكتب، ولكن مرة أخرى، لا تتردد في استخدام أي شيء يطفو قاربك.

يمكن العثور على تعليمات تثبيت Cocoapods على هذا الموقع.

يمكن العثور على تعليمات تثبيت NPM على هذا الموقع.

إنشاء فئاتنا

سنقوم بتنفيذ 3 فئات: المالك والكلب والسلالة.

سيقتضي نموذجنا أن

  • يمكن أن يكون للمالك عدة كلاب
  • يمكن أن يكون للكلب سلالة واحدة فقط

خصائصنا ستكون:

  • المالك
    • الاسم (سلسلة)
    • العمر (رقم)
    • العنوان (سلسلة)
    • لديه كلاب (علاقة بالكلب، حيث يمكن أن يكون للمالك عدة كلاب)
  • كلب
    • الاسم (سلسلة)
    • تاريخ الميلاد (تاريخ)
    • السلالة (مؤشر للسلالة، حيث أن الكلب له سلالة واحدة فقط)
  • السلالة
    • الاسم (سلسلة

إنشاء هذه الفئات بيانياً أو برمجياً وتعبئتها ببعض البيانات. انتهى الأمر بفئاتي هكذا

screen-shot-2019-08-15-at-12-08-46

السلالة

screen-shot-2019-08-15-at-13-50-39

كلب

screen-shot-2019-08-15-at-12-15-45

المالك

أحضر الكود السحابي يا عزيزي!

حان وقت بعض الرموز السحابية. لكن هذه المرة أريد أن أتعمق في ذلك أيضًا.

هل أخبرتك من قبل أن الكود السحابي متوافق مع وحدات NPM؟ إنه كذلك! ويمكن أن يوفر لك الكثير من الوقت!

هل تعرف وظيفة الأشياء الرائعة التي أردت الحصول عليها، وقد قام بها شخص آخر بالفعل؟ حسنًا، إذا كانت وحدة NPM، يمكنك استخدامها!

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

لذا سيبدو ملف pack.json الخاص بي هكذا

{
      "التبعيات": {
           "لحظة": "*"
      }
}

تعني * أنني سأستخدم أحدث إصدار.

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

// تثبيت الوحدة النمطية Moment NPM Module
لحظة الثابتة = تتطلب('لحظة')

Parse.Cloud.defined("retrieveOwnersOwnersOrderedByAgeDescending"، async req => {
    /*
        تسترجع هذه الدالة جميع المالكين مرتبين حسب العمر تنازليًا.
        إذا لم يكن هناك مالكون، يتم استرجاع مصفوفة فارغة.
    */
    const query = جديد Parse.Query("المالك"); 
    استعلام.تنازلي("العمر")
    كونت النتائج = انتظر query.find();

    إرجاع النتائج;
});

Parse.Cloud.defined("retrieveAllGermanGhepherds", async req => {
    /*
        تسترجع هذه الدالة الكلاب التي لديها سلالة "الراعي الألماني"
        يتم استرجاع جميع خصائص الكلاب.
        إذا لم يكن هناك كلاب، يتم استرجاع مصفوفة فارغة.
    */
    const breedQuery = جديد Parse.Query("سلالة");
    سلالةQuery.equTo("اسم"، "الراعي الألماني") 
    const query = جديد Parse.Query("كلب"); 
    الاستعلام.matchesQuery("سلالة"، breedQuery);
    تشكل النتائج = انتظر quaitery.find();
    إرجاع النتائج;
});

Parse.Cloud.defined("retrieveDogIncludingBreedByName", async req => {
    /*
        تسترجع هذه الدالة تفاصيل الكلب المحددة بما في ذلك تفاصيل سلالته (الاسم) حسب اسم الكلب
        يتم استرجاع جميع خصائص الكلاب والسلالة.
        إذا لم يكن هناك كلاب، يتم استرجاع لا شيء.
    */
    const query = جديد Parse.Query("كلب"); 
    الاستعلام.equTo("اسم"، req.params.name);
    يتضمن الاستعلام("سلالة")
    تشكل النتائج = انتظر quaitery.find();
    إرجاع النتائج;
});

Parse.Cloud.define("retrieveveDogsNamesWithAgesInMonths"، async req => {
    /*
        تسترجع هذه الدالة أسماء الكلاب مع تحويل خاصية عيد الميلاد إلى شهور باستخدام وحدة NPM لحظة
        يتم استرجاع اسم الكلاب فقط وحساب العمر بالأشهر.
        إذا لم يكن هناك كلاب، يتم استرجاع مصفوفة فارغة.
    */
    دع الكلاب = [];
    const query = استعلام جديد Parse.Query("كلب"); 
    كونت النتائج = انتظر quaitery.find();

    بالنسبة إلى (دع i = 0؛ i < results.length؛ i ++){{
        // حساب العمر بالأشهر باستخدام وحدة NPM Module Moment
        دع ageInMonths = moment.duration(moment().diff(results[i].get("birthday"))).humanize();
        
        دعونا newDog = {
            "اسم الكلب": results[i].get("اسم"),
            "dogAgeAgeInMonths": ageInMonths
        }

        dogs.push(newDog);
    }

    إرجاع الكلاب;
});

جاء ملف schema.Graphql الخاص بي الذي يعرض طرقي الأربعة على هذا النحو:

تمديد نوع الاستعلام {
  getAllOwnersAgeDescending: [OwnerClass!] @resolve(to: "retrieveOwnersOwnersOrderedByAgeDescending")
  getAllAllGermanShepherds: [فئة الكلب!]! @resolve(to: "retrieveveAllGermanShepherds")
  getThisDogThisDogWithBreed (الاسم: سلسلة): [DogClass!]! @resolve(to: "retrieveveDogIncludingBreedByreedByName")
  getDogsAgesInMonths: [DogAge!]!  @resolve(to: "retrieveDogsNamesWithAgesInMonths")
}

اكتب DogAge {
    اسم الكلب: سلسلة
    dogAgeInMonths: سلسلة!
}

إن لم تفهم الصياغة، راجع هذه المقالة في قسم “خطوة إضافية صغيرة”.
لاحظ فقط [DogAge!]! في getDogsAgesAgesInMonths. بما أنني سأقوم باسترداد كائن تم إنشاؤه من قبل النظام، فلن يكون له مخطط لتفسير GraphQL، لذلك يجب أن أقوم بإنشاء النوع أيضًا حتى يتمكن عميلنا من تفسيره.

اختبار… اختبار…

حان الوقت لبعض الاختبارات!

دعنا نذهب إلى وحدة تحكم Parse GraphQL الخاصة بنا ونجري استعلاماتنا، ونتحقق من نتائجها:

الاستعلام عن getAllOwnersAgeDescending:

استعلام{
  getAllAllOwnersAgeDescending {
    الاسم
    العمر
    العنوان
  }
}

screen-shot-2019-08-16-at-09-17-50

استعلام عن getAllAllGermanShepherds:

استعلام {
  getAllAllGermanShepherds {
    الاسم
    عيد ميلاد
  }
}

screen-shot-2019-08-16-at-09-46-24

استعلام عن getThisDogThisDogWithBreed:

استعلام{
  getThisDogThisDogWithBreed(الاسم: "فيدو"){
    الاسم
    عيد ميلاد
    السلالة{
      الاسم
    }
  }
}

screen-shot-2019-08-16-at-09-50-05

استعلام عن getDogsAgesAgesInMonths:

استعلام{
  getDogsAgesAgesInMonths
}

screen-shot-2019-08-16-at-09-50-51

كل شيء يعمل! عظيم! الآن حان الوقت لـ

بعض ترميز XCoding

لقد حصلنا على كل ما نحتاجه من Back4app جاهزًا ويعمل. حان الوقت لاستهلاك ذلك على XCode.

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

إذا لم تكن قد تابعت هذا المقال بعد، أقترح عليك أن تفعل ذلك لأنه مفصل للغاية.

لنبدأ بإنشاء التطبيق وتثبيت عميل Apollo كما هو موضح في المقالة.

بعد ذلك، افتح ملف Main.storyboard الخاص بك، وانقر على زر الكائنات في الزاوية العلوية اليمنى واسحب وإسقاط طريقة عرض الجدول إلى وحدة تحكم العرض:

screen-shot-2019-08-19-at-13-00-29

غيِّر حجم طريقة عرض الجدول الخاص بك ليتطابق مع كامل طريقة عرض وحدة تحكم العرض عن طريق سحب الزوايا:

screen-shot-2019-08-19-at-13-01-01

وأنشئ قيودًا لجميع الجوانب الأربعة بالنقر على زر إضافة قيود جديدة في أسفل يمين الشاشة. انقر على الجوانب الأربعة (العلامات الحمراء) وانقر على زر إضافة قيود لتعيين تلك القيود الجديدة:

screen-shot-2019-08-19-at-13-01-17

الآن، مع تحديد طريقة عرض الجدول (انقر عليها للتحديد)، دعنا نضيف خلية نموذجية. انقر فوق مفتش السمات في أعلى اليمين، واستبدل 0 ب 1 في مربع خلايا النموذج الأولي:

screen-shot-2019-08-19-at-13-01-30

الآن، انقر على خلية النموذج الأولي المنشأة حديثًا لتحديدها، وأعطها معرّفًا جيدًا: “خلية”.
سنستخدمه لاحقًا في الكود لتحديد تلك الخلية.

screen-shot-2019-08-19-at-13-13-07

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

screen-shot-2019-08-19-at-13-02-09

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

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

ثم انقر على زر التحكم فوق طريقة عرض الجدول واسحبه إلى الشيفرة:

screen-shot-2019-08-19-at-17-10-53

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

screen-shot-2019-08-19-at-17-08-14

بعد الانتهاء من ذلك، يجب أن يكون لديك منفذ لطيف متصل (لاحظ الدائرة الصغيرة المملوءة على رقم السطر) حتى نتمكن الآن من استدعاء الشيفرة لطريقة عرض الجدول تلك:

screen-shot-2019-08-19-at-17-08-34

بعد الانتهاء من كل ذلك، يمكننا الانتقال إلى ملف ViewController.swift الخاص بنا لأنه حان الوقت لـ

ملف GraphQL الخاص بنا

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

الاستعلام findAllAllOwners{
    getAllAllOwnersAgeDescendend{
        الاسم
        العمر
        العنوان
    }
}

استعلام البحث عن جميع الرعاة الألمان{
    getAllAllGermanShepherds {
        الاسم
    }
}

استعلام findThisDog (الاسم: $ الاسم: سلسلة!) { {
    getThisDogThisDogWithBreed(الاسم: $ اسم){
        الاسم
        عيد ميلاد
        سلالة{
            اسم
        }
    }
}

استعلام الأعمار في الأشهر{
    getDogsAgesAgesInMonths
}

بعض شيفرة Swift

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

func tableView(_ tableView: UITableView، numberOfRowsInSection section: Int) -> Int

و

func tableView(_ tableView: UITableView، cellForRowAt indexPath: IndexPath) -> UITableViewCell

لن أتناول الكثير عن ذلك لأنهما موثقان في الشيفرة. فقط ضع في اعتبارك أن هاتين الطريقتين إلزاميتان لكي تعمل طريقة عرض الجدول.

يجب أن تبدو شفرتك الكاملة هكذا:

//
// // ViewController.swift
// GraphQLApollo
//
// تم إنشاؤها بواسطة Venom في 19/08/19.
// حقوق الطبع والنشر © 2019 فينوم. جميع الحقوق محفوظة.
//

استيراد UIKit
استيراد Apollo

صنف ViewController: UIVController، UITableViewDelegate، UITableViewDataSource {
    @IBOutlet ضعيف var tableView: UITableView!
    
    var list = [] ك [String] // ستحتوي هذه المصفوفة على القيم التي سنعرضها
    
    // تهيئة عميل Apollo.
    // المزيد عن ذلك هنا: https://www.back4app.com/docs/ios/swift-graphql
    دع Apollo: ApolloClient = {
        دع التهيئة = URLSConfiguration.default.com
        configuration.httpAdditionalHeaders = [
            "X-Parse-Application-Id": "lAcIOGR0nd7R7Ru4uMqovhNAUDPI6tMsrOI9Kuyr",
            "X-Parse-Client-Key": "f1wwm6wm6uWqQoxazazys3QrtY4FKuQuxYVNYJMYQJMYQJP"
        ]
        
        دع عنوان url = URL(سلسلة: "https://parseapi.back4app.com/graphql")!
        
        إرجاع ApolloClient(
            networkTransport: HTTPNetworkTransTransport(
                url: url,
                التكوين: التكوين
            )
        )
    }()
    
    تجاوز func func viewDidLoad() {{
        super.viewDidDidLoad()
        // قم بأي إعداد إضافي بعد تحميل العرض.
        
        apollo.fetch(query: FindAllOwnersQuery()) { النتيجة في
            حراسة دع البيانات = محاولة؟ result.get().data وإلا { إرجاع }
            
            للاسم في البيانات.getAllAllOwnersAgeDescending {
                //إلحاق كل اسم بمصفوفة القائمة الخاصة بنا
                self.list.append(name.name!)
            }
            
            // سيفرض السطر أدناه إعادة تحميل طريقة عرض الجدول بعد استرداد البيانات
            DispatchQueue.main.async { self.tableView.reloadData() }
        }
    }
    
    func tableView(_ tableView: UITableView، numberOfRowsInSection section: Int) -> Int {
        // تُستدعى هذه الدالة بواسطة طريقة عرض الجدول من خلال مصدر البيانات والمندوب.
        // تُرجع فقط عدد العناصر التي ستعرضها طريقة عرض الجدول.
        // وهي إلزامية لكي تعمل طريقة عرض الجدول.
        إرجاع list.count
    }
    
    func tableView(_ tableView: UITableView، cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // يتم استدعاء هذه الدالة من خلال طريقة عرض الجدول من خلال مصدر البيانات والمندوب.
        // تنشئ الخلايا التي سيتم عرضها بالمعرّف الذي قمنا بتعيينه في لوحة القصة
        // وهي إلزامية لكي تعمل طريقة عرض الجدول.
        دع الخلية = UITableViewCell(النمط: UITableViewCell.CellStyle.default، معرف إعادة الاستخدام: "خلية")
        cell.textLabel?.text = list[list[indexPath.row]
        إرجاع (الخلية)
    }
}

لنقم بتشغيله!

حان وقت تشغيل شفرتنا! اضغط على الأمر + R وإذا كان كل شيء على ما يرام، يجب أن ترى أسماءنا في عرض الجدول:

screen-shot-2019-08-19-at-17-26-09

رائع، أليس كذلك؟
الآن يمكننا حتى تغيير شفرتنا لتنفيذ طرق GraphQL الأخرى الخاصة بنا ونرى كيف ستعمل!

دعنا نغير استعلام GraphQL الخاص بنا لتنفيذ طريقة getAllGermanShepherds:

    تجاوز func func viewDidLoad() { {
        super.viewDidLoad()
        // قم بأي إعداد إضافي بعد تحميل طريقة العرض.
        
        apollo.fetch(استعلام: FindAllAllGermanShepherdsQuery()) { النتيجة في
            حراسة دع البيانات = محاولة؟ result.get().data وإلا { إرجاع }
            
            طباعة(data.getAllAllGermanShepherds)
            
            للاسم في data.getAll.getAllGermanShepherds {
                //إلحاق كل اسم بمصفوفة القائمة الخاصة بنا
                self.list.append(name.name!)
            }
            
            // سيفرض السطر أدناه إعادة تحميل طريقة عرض الجدول بعد أن نسترجع البيانات
            DispatchQueue.main.async { self.tableView.reloadData() }
        }
    }

والنتيجة…

screen-shot-2019-08-20-at-08-45-40

ماذا لو أردنا تمرير متغير إلى استعلامنا؟

    تجاوز func viewDidLoad() { {
        super.viewDidDidLoad()
        // قم بأي إعداد إضافي بعد تحميل العرض.
        
        apollo.fetch(استعلام: FindThisDisDogQuery(الاسم: "فيدو")) { النتيجة في
            حراسة دع البيانات = محاولة؟ result.get().data وإلا { إرجاع }
            
            طباعة(data.getThisDogThisDogWithBreed)
            
            للاسم في data.getThisDogThisDogWithBreed {
                //إلحاق كل اسم بمصفوفة القائمة الخاصة بنا
                self.list.append(name.name! + " - " - " + (name.breed?.name!)!)!
            }
            
            //السطر أدناه سيفرض إعادة تحميل طريقة عرض الجدول بعد أن نسترجع البيانات
            DispatchQueue.main.async { self.tableView.reloadData() }
        }
    }

والآن نحن نعلم أن فيدو هو كلب الصلصال:

screen-shot-2019-08-20-at-08-52-29

وماذا عن تلك الطريقة التي تُعيد نوعًا جديدًا؟ لنختبرها أيضًا:

   تجاوز func func viewDidLoad() { {
        super.viewDidDidLoad()
        // قم بأي إعداد إضافي بعد تحميل العرض.
        
        apollo.fetch(query: AgesInMonthsQuery())) { النتيجة في
            حراسة دع البيانات = محاولة؟ result.get().data وإلا { إرجاع }

            طباعة(data.getDogsAgesAgesInMonths)

            بالنسبة للكلاب في data.getDogsAgesAgesInMonths {
                //إلحاق كل اسم بمصفوفة القائمة الخاصة بنا
                self.list.append(dog.dogName + " - " - " + dog.dogAgeAgeInMonths)
            }

            //سيفرض السطر أدناه إعادة تحميل طريقة عرض الجدول بعد استرجاع البيانات
            DispatchQueue.main.async { self.tableView.reloadData() }
        }
    } 

والنتيجة

screen-shot-2019-08-20-at-10-16-21

الخلاصة

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

الآن بعد أن أصبحت قادرًا على إنشاء تدفق عمل كامل للتطبيق، يسهل إنشاؤه وصيانته بمرور الوقت، السؤال الآن هو: ما الذي ستقوم بإنشائه بعد ذلك؟

آمل أن تكون قد استمتعت بهذا! لدينا المزيد قريبًا! ابقوا معنا!

ما هي البرامج التي يمكن استخدامها لاستخدام وظائف السحابة في تطبيق Swift؟

يعتمد الأمر على اختيارك. يُنصح باستخدام برنامج يسهل عليك استخدامه وتشغيله. استخدمتُ البرنامجين المذكورين أدناه في تجربتي العملية.
-Cocoapods لإدارة حزم IOS
-NPM لإدارة حزم سطح المكتب

ما هو سحر NPM؟

يتوافق كود السحابة مع وحدات NPM. هذا أمر رائع، إذ سيساعدك على توفير الكثير من الوقت، كما سيمنحك أفضلية على منافسيك. لذا، فإن توافق NPM مع أكواد السحابة سيعزز من أدائك.


Leave a reply

Your email address will not be published.