أداة مخصصة لن تعترض طريقك في تطبيقك

عشية بدء الدورة الأساسية "مطور iOS" ، أعددنا لك ترجمة أخرى مثيرة للاهتمام.










: WWDC 2020, . , , — - , . , , - WWDC



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



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



استعدادًا لمؤتمر WWDC 1 الأسبوع المقبل ، شاهدت (إعادة) محاضرتين من WWDC السابقة. على أي حال ، فاتني تمامًا إعادة كتابة الأدوات الأساسية لتوحيدها وتسهيل إنشاء أدوات مخصصة لـ Xcode 10. أيضًا ، أثبت WWDC 2019 أنه مقدمة رائعة للأدوات التي كنت أفتقدها طوال هذه السنوات.



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



لكن لنبدأ من البداية: أريد أن يقوم أي منكم ممن استخدم Charles أو Wireshark من قبل لتصحيح أخطاء تطبيقك ، أو طور تطبيقًا يقوم بإجراء الكثير من طلبات HTTP ، ليتمكن من إنشاء أداة تتبع HTTP مخصصة لتطبيقك ، أو على الأقل إطار عمل. سيبدو الأمر كما يلي:







لقد استغرق الأمر يومًا واحدًا تقريبًا لإنشاء هذا النموذج الأولي وتصحيحه (بعد مشاهدة مقاطع فيديو WWDC ذات الصلة). إذا لم تكن مهتمًا بأي شيء آخر غير الكود ، فيمكنك رؤيته هنا .



نظرة عامة



أسهل طريقة لإنشاء أداة مخصصة هي استخدام os_signpost ، وهو بالضبط ما سنفعله هنا. يمكنك استخدامه لتسجيل مؤشرات .event أو .begin و .end . ثم تقوم بإعداد أداة مخصصة لتحليل فترات os_signpost هذه واستخراج القيم الإضافية التي قمت بتسجيل الدخول إليها ، وإعداد كيفية عرضها على الرسم البياني ، وكيفية تجميعها ، وأي منها يتم تصفيته ، وكيفية تمثيل هياكل القوائم أو الأشجار / المخططات الانسيابية في جزء تفاصيل الأداة. ...



نريد إنشاء أداة تعرض جميع طلبات HTTP التي تمر عبر مكتبة الويب الخاصة بنا على شكل فترات (بداية + نهاية) حتى نتمكن من معرفة المدة التي تستغرقها وربطها بالأحداث الأخرى التي تحدث في تطبيقنا. بالنسبة لهذه المقالة ، أستخدم Alamofire كمكتبة للشبكات للأداة و Wordpress كتطبيق التنميط الخاص بي ، وذلك ببساطة لأنها مفتوحة المصدر. ولكن يمكنك بسهولة تكييف كل الأكواد مع مكتبة الشبكة الخاصة بك.



الخطوة 0: تحقق من تطبيق Instruments



  1. ( 411 WWDC 2019) — . «Orientation», , (instruments), (tracks), (lanes), (traces), (templates), (detail view) . .
  2. ( 410 WWDC 2018), , . , «Architecture» ( , , ) «Intermediate». , , , - . , , . , .




1: signpost-



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



NotificationCenter.default.addObserver(forName: Notification.Name.Task.DidResume, object: nil, queue: nil) { (notification) in
    guard let task = notification.userInfo?[Notification.Key.Task] as? URLSessionTask,
        let request = task.originalRequest,
        let url = request.url else {
            return
    }
    let signpostId = OSSignpostID(log: networking, object: task)
    os_signpost(.begin, log: SignpostLog.networking, name: "Request", signpostID: signpostId, "Request Method %{public}@ to host: %{public}@, path: %@, parameters: %@", request.httpMethod ?? "", url.host ?? "Unknown", url.path, url.query ?? "")
}
NotificationCenter.default.addObserver(forName: Notification.Name.Task.DidComplete, object: nil, queue: nil) { (notification) in
    guard let task = notification.userInfo?[Notification.Key.Task] as? URLSessionTask else { return }
    let signpostId = OSSignpostID(log: networking, object: task)
    let statusCode = (task.response as? HTTPURLResponse)?.statusCode ?? 0
    os_signpost(.end, log: SignpostLog.networking, name: "Request", signpostID: signpostId, "Status: %@, Bytes Received: %llu, error: %d, statusCode: %d", "Completed", task.countOfBytesReceived, task.error == nil ? 0 : 1, statusCode)
}




عندما يبدأ الطلب ، نقوم بتسجيل الإشارة .begin، وعندما يكتمل ، نضيف العلامة .end. لمطابقة نهاية المكالمة مع بداية المكالمة المقابلة يتم استخدامها signpostIdللتأكد من أننا نغلق الفاصل الزمني الصحيح في حالة حدوث طلبات متعددة على التوازي. من الناحية المثالية ، يجب أن نخزن signpostIdفي كائن الطلب للتأكد من أننا نستخدم نفس الشيء لـ .beginو .end. ومع ذلك ، لم أرغب في تحرير النوع Requestفي Alamofire ، لذلك قررت استخدام OSSignpostID(log:, object:)كائن ID وتمريره إليه. نستخدم الكائن الأساسي URLSessionTaskلأنه في كلتا الحالتين سيكون هو نفسه ، مما يسمح OSSignpostID(log:, object:)لنا بإرجاع نفس المعرف عندما يتم استدعاؤه عدة مرات.



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



الخطوة 2: إنشاء مشروع أداة مخصصة جديد في Xcode.



اتبع الخطوات من Create Custom Instruments (الجلسة 410 من WWDC 2018) أو تعليمات تطبيق Instruments - قم بإنشاء مشروع Toolbox لإنشاء مشروع مربع أدوات جديد في Xcode. سيعطيك هذا مشروع Xcode أساسي مع .instrpkgملف. سنشير إلى كل التفاصيل هناك.



الخطوة 3: افعل الباقي



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



المخطط



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



<os-signpost-interval-schema>
	<id>org-alamofire-networking-schema</id>
	<title>Alamofire Networking Schema</title>

	<subsystem>"org.alamofire"</subsystem>
	<category>"networking"</category>
	<name>"Request"</name>

	<start-pattern>
	    <message>"Request Method " ?http-method " to host: " ?host ", path: " ?url-path ", parameters: " ?query-parameters</message>
	</start-pattern>
	<end-pattern>
	    <message>"Status: " ?completion-status ", Bytes Received: " ?bytes-received ", error: " ?errored ", statusCode: " ?http-status-code</message>
	</end-pattern>

	<column>
	    <mnemonic>column-http-method</mnemonic>
	    <title>HTTP Method</title>
	    <type>string</type>
	    <expression>?http-method</expression>
	</column>
	<!--      -->
</os-signpost-interval-schema>




mnemonicهو المعرف الذي ستشير إليه في هذا العمود لاحقًا. لسبب ما وجدت أنه من الغريب بعض الشيء تسمية الأعمدة بنفس المتغيرات ، لذلك أضع بادئة أمامهم column. لكن ، على حد علمي ، ليست هناك حاجة للقيام بذلك. تتكون



أداة



الأداة من تعريف أساسي:



<instrument>
    <id>org.alamofire.networking.instrument</id>
    <title>Alamofire</title>
    <category>Behavior</category>
    <purpose>Trace HTTP calls made via Alamofire, grouped by method, host, path, etc.</purpose>
    <icon>Network</icon>
    
    <create-table>
        <id>alamofire-requests</id>
        <schema-ref>org-alamofire-networking-schema</schema-ref>
    </create-table>

    <!--     -->
</instrument>




انها بسيطة جدا. معظم هذه الحقول عبارة عن نص حر أو مرتبطة بالمواد التي حددتها سابقًا ( schema-ref). ولكن categoryأيضا iconيمكن أن يكون سوى مجموعة صغيرة من القيم المحددة هنا و هنا .



رسم بياني داخل أداة



يحدد الرسم البياني الجزء الرسومي لواجهة مستخدم الأداة ، التمثيل المرئي الذي تراه في منطقة المسار. يبدو شيء من هذا القبيل:



<instrument>
    <!--    -->
    <graph>
        <title>HTTP Requests</title>
        <lane>
            <title>the Requests</title>
            <table-ref>alamofire-requests</table-ref>
            
            <plot-template>
                <instance-by>column-host</instance-by>
                <label-format>%s</label-format>
                <value-from>column-url-path</value-from>
                <color-from>column-response</color-from>
                <label-from>column-url-path</label-from>
            </plot-template>
        </lane>
    </graph>
    <!--    --> 
</instrument>




يمكن أن يكون لديك ممر مختلف ، ويمكنك استخدام قالب قطعة الأرض لتنفيذ عدد ديناميكي من قطع الأراضي لكل حارة. يحتوي المثال الخاص بي على مثال لرسم بياني بسيط . لست متأكدا من السبب graphو laneلها عناوين. بالإضافة إلى ذلك ، يتلقى كل مخطط في plot-templateأيضًا تسمية من label-format.



قائمة أو تجميع أو أي شيء لعرض مفصل



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



<instrument>
    <!--    -->
    <aggregation>
        <title>Summary: Completed Requests</title>
        <table-ref>alamofire-requests</table-ref>
        <slice>
                <column>column-completion-status</column>
                <equals><string>Completed</string></equals>
        </slice>
        <hierarchy>
            <level>
                <column>column-host</column>
            </level>
            <level>
                <column>column-url-path</column>
            </level>
        </hierarchy>
        
        <column><count/></column>
        <column><average>duration</average></column>
        <column><max>duration</max></column>
        <column><sum>column-size</sum></column>
        <column><average>column-size</average></column>
    </aggregation>
    <!--    --> 
</instrument>




تبدو القائمة كما يلي:



<instrument>
    <!--    -->
    <list>
        <title>List: Requests</title>
        <table-ref>alamofire-requests</table-ref>
        <column>start</column>
        <column>duration</column>
        <column>column-host</column>
        <!--   ->
    </list>
    <!--    -->
</instrument>




مادة إضافية



هذا ، في الواقع ، كل شيء. ومع ذلك ، لم تقم بأكثر مما وصفه فيديو WWDC ، وقد وعدت بسد بعض الفجوات.



تحتوي أداة المثال الخاص بي على بعض الأشياء اللطيفة. تعبير CLIPS



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

<engineering-type-track>لتحديد التسلسل الهرمي الخاص بك ، ثم قم بإضافة (تكبير) ل مستويات مختلفة من التسلسل الهرمي ل إضافة الرسوم البيانية و جهات النظر التفاصيل . أيضًا ، لا تنس تنشيط الوظائف الإضافية داخل الأداة المعنية.



مزيد من الإجراءات



إذا لم تكن قد صادفتها من الروابط السابقة حتى الآن ، فهناك بالفعل مساعدة كاملة لكل ما يمكنك وضعه في .instrpkgالملف. على سبيل المثال ، سيخبرك بالعناصر <instrument>أو الرموز التي يمكنك اختيارها لأداتك. نقطة واحدة مهمة: النظام مهم. لذلك ، على سبيل المثال ، في <instrument>، <title>يجب أن يظهر قبل <category>ذلك ، وإلا فسيكون الوصف غير صالح.



راجع إنشاء الأدوات المخصصة (الجلسة 410 من WWDC 2018) مرة أخرى لملاحظة التفاصيل التي قد تحتاجها. هناك أيضًا نموذج لرمز من جلسة WWDC 2019 حيث وجدت مثالًا للاستخدام <engineering-type-track>.



CLIPS هي اللغة المستخدمة لكتابة نماذج مخصصة (مصممي النماذج - لن نغطي ذلك هنا) ، ولكن يمكن استخدامها أيضًا للتعبيرات القصيرة أثناء تعريفات الأعمدة. الوثائق اللغوية أكثر شمولاً مما تحتاجه. الشيء الرئيسي الذي ربما تحتاج إلى معرفته لكتابة تعبير بسيط هو أن CLIPS تستخدم تدوين البادئة ، لذلك ?a + ?bعليك الكتابة بدلاً من ذلك (+ ?a ?b).



المزيد من المقالات حول الأدوات المخصصة



Igor على إنشاء صناديق أدوات مخصصة في Xcode



تصحيح



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



ما لم أحسبه بعد



  • كيفية استخدام القيم التي توفرها لك Instruments بشكل افتراضي ويتم عرضها في واجهة المستخدم (على سبيل المثال ، المدة) في تعبيرات تعريفات الأعمدة (على سبيل المثال ، لإنشاء عمود معدل البث بالباود عن طريق قسمة البايتات المستلمة على المدة).
  • كيفية عرض أي شيء في منطقة التفاصيل الإضافية. يبدو أنه مخصص لمكدس المكالمات فقط. أود أن أعرض ، على سبيل المثال ، نص JSON للطلب المحدد ، لكنني لم أجد أي مثال يوضح ذلك.




ما هي هذه الأداة قادرة على



لا يزال العمل قيد التقدم



قم بتنزيله وانظر بنفسك.



الحواشي



  1. حسنًا ، كانت هناك بالفعل أسباب أخرى.
  2. الكود الكامل لتسجيل الدخول في المثال الخاص بي موجود في ملف Logger.swift . يُفترض أن يكون لـ Alamofire 4.8 ، لأن هذا هو ما يستخدمه الإصدار الحالي من تطبيق Wordpress iOS ، على الرغم من إصدار Alamofire 5 بالفعل وقت كتابة هذا التقرير. بسبب الإخطارات ، من السهل إضافة رمز التسجيل هذا دون تغيير Alamofire نفسه ، ولكن إذا كان لديك مكتبة شبكات مخصصة ، فقد يكون من الأسهل إضافة إدخال إلى المكتبة نفسها للوصول إلى مزيد من التفاصيل.





بداية سريعة لتطوير iOS (ندوة مجانية على الويب)






اقرأ أكثر






All Articles