{"id":"l-sw-2-2","courseId":"swift-essentials","lang":"ar","kind":"lesson","summary":"استبدل النصوص الهشّة بالـ enums، وأرفق بيانات بكل حالة عبر القيم المرتبطة، ودع جمل switch الشاملة تجد كل مكان يحتاج إلى معالجة حالة جديدة.","html":"<p>في القسم السابق كان تصنيف المصروف <code dir=\"ltr\">String</code>. وهذا يعمل إلى أن يكتب أحدهم <code dir=\"ltr\">&quot;Fod&quot;</code>، أو <code dir=\"ltr\">&quot;food&quot;</code> في مكان و<code dir=\"ltr\">&quot;Food&quot;</code> في مكان آخر، فيُسقط المجموع الشهري نصف مشترياتك من البقالة بصمت. لم يكن في النوع ما يحدّد النصوص الصالحة. أما الـ <strong>enum</strong> (التعداد) فيقول ذلك بالضبط: هذه هي القائمة الكاملة للقيم الممكنة، ولا شيء غيرها مسموح.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">الـ enums ذات القيم الخام</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Category.swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">enum</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Category</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">CaseIterable </span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> food</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> transport</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> housing</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> fun</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> title: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        rawValue.capitalized</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> symbolName: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        switch</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> self</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .food</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"fork.knife\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .transport</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"bus\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .housing</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"house\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .fun</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"ticket\"</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>صار لـ <code dir=\"ltr\">Category</code> أربع قيم بالضبط. اكتب <code dir=\"ltr\">.fod</code> وستفشل الترجمة. والجزء <code dir=\"ltr\">: String</code> يعطي كل حالة <strong>قيمة خام</strong> (raw value)، وهي افتراضيًا اسم الحالة كنص (<code dir=\"ltr\">Category.food.rawValue</code> تساوي <code dir=\"ltr\">&quot;food&quot;</code>)، وهي ما ستحفظه على القرص وتقرؤه من JSON لاحقًا. أما الاتجاه المعاكس فقابل للفشل، لأن ليس كل نص تصنيفًا: <code dir=\"ltr\">Category(rawValue: &quot;fun&quot;)</code> تعطي <code dir=\"ltr\">.fun</code>، و<code dir=\"ltr\">Category(rawValue: &quot;Fun&quot;)</code> تعطي <code dir=\"ltr\">nil</code>.</p>\n<p>يطلب <code dir=\"ltr\">CaseIterable</code> من الـ compiler أن يولّد <code dir=\"ltr\">Category.allCases</code>، وهي مصفوفة بكل الحالات بترتيب تعريفها. سيمرّ منتقي التصنيفات في Pocket Budget عليها، فإضافة حالة تضيف صفًا إلى المنتقي دون أي جهد.</p>\n<p>يمكن أن تحتوي الـ enums خصائص محسوبة وmethods، تمامًا مثل الـ structs. تربط <code dir=\"ltr\">symbolName</code> كل حالة باسم أيقونة من SF Symbols، والـ <code dir=\"ltr\">switch</code> بداخلها بلا <code dir=\"ltr\">default</code>.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">جمل switch الشاملة ميزة</h2>\n<p>لنفترض أنك أضفت <code dir=\"ltr\">case gifts</code> الشهر القادم. ستفشل الترجمة فورًا عند <code dir=\"ltr\">symbolName</code> مع “switch must be exhaustive”، وعند كل <code dir=\"ltr\">switch</code> أخرى على <code dir=\"ltr\">Category</code> في المشروع. لقد أعدّ الـ compiler قائمة مهامك. قارن ذلك بنسخة النصوص، حيث يقع التصنيف الجديد بهدوء في أي فرع <code dir=\"ltr\">default</code> كان موجودًا، ويعرض الأيقونة الخطأ في الإنتاج.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>إضافة default إلى switch على enum</span></p>\n<p><code dir=\"ltr\">default: &quot;questionmark&quot;</code> يُخفي خطأ اليوم ويجعل خطأ الغد غير مرئي. حين تضيف <code dir=\"ltr\">.gifts</code>، لا شيء يخبرك أن هذه الـ switch لم تتعلّم عنها شيئًا. في الـ enum الذي تملكه، اسرد كل حالة صراحةً ودع الـ compiler يتولّى تذكيرك بكل حالة تنساها.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">القيم المرتبطة: حالات تحمل بيانات</h2>\n<p>القيم الخام ثابتة لكل حالة. لكن بعض البيانات تختلف من instance إلى آخر. يسجّل Pocket Budget طريقة دفع المصروف، وكل طريقة تحتاج تفاصيل مختلفة:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">PaymentMethod.swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">enum</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> PaymentMethod</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> cash</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(lastFour: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> transfer</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(bank: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, reference: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> lunch: PaymentMethod </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .cash</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> groceries: PaymentMethod </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">lastFour</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"4242\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> rent: PaymentMethod </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">transfer</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">bank</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Monzo\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">reference</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"RENT-10\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span></code></pre></div>\n<p>لكل حالة شكلها الخاص. الدفع النقدي لا يحمل شيئًا، والدفع بالبطاقة يحمل أربعة أرقام، والتحويل يحمل اسم البنك ومرجعًا اختياريًا. لو استخدمت struct لاحتجت إلى ثلاث خصائص optional وتعليق يشرح أيّها يُملأ ومتى. أما الـ enum فيجعل التركيبات غير الصالحة، مثل دفع نقدي معه اسم بنك، مستحيلة البناء أصلًا.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 210\" role=\"img\" aria-labelledby=\"l-sw-2-2-t1\"><defs><marker id=\"arrow-l-sw-2-2-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-sw-2-2-t1\">يتفرّع الـ enum المسمّى PaymentMethod إلى ثلاث حالات: cash بلا بيانات، وcard تحمل lastFour، وtransfer تحمل bank ومرجعًا اختياريًا reference.</title>\n  <rect class=\"d-box-primary\" x=\"250\" y=\"15\" width=\"180\" height=\"50\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"340\" y=\"46\" text-anchor=\"middle\">PaymentMethod</text>\n  <path class=\"d-arrow\" d=\"M300 65 L120 115\" marker-end=\"url(#arrow-l-sw-2-2-1)\"/>\n  <path class=\"d-arrow\" d=\"M340 65 L340 115\" marker-end=\"url(#arrow-l-sw-2-2-1)\"/>\n  <path class=\"d-arrow\" d=\"M380 65 L560 115\" marker-end=\"url(#arrow-l-sw-2-2-1)\"/>\n  <rect class=\"d-box\" x=\"40\" y=\"120\" width=\"160\" height=\"70\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"120\" y=\"150\" text-anchor=\"middle\">.cash</text>\n  <text class=\"d-label-muted\" x=\"120\" y=\"172\" text-anchor=\"middle\">بلا بيانات</text>\n  <rect class=\"d-box-accent\" x=\"260\" y=\"120\" width=\"160\" height=\"70\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"340\" y=\"150\" text-anchor=\"middle\">.card</text>\n  <text class=\"d-label-muted\" x=\"340\" y=\"172\" text-anchor=\"middle\">lastFour</text>\n  <rect class=\"d-box-success\" x=\"480\" y=\"120\" width=\"180\" height=\"70\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"570\" y=\"150\" text-anchor=\"middle\">.transfer</text>\n  <text class=\"d-label-muted\" x=\"570\" y=\"172\" text-anchor=\"middle\">bank, reference?</text>\n</svg><figcaption>enum واحد وثلاث حالات بأشكال مختلفة</figcaption></figure>\n<h2 id=\"sec-4\" tabindex=\"-1\">استخراج البيانات من جديد</h2>\n<p>تقرأ القيم المرتبطة عبر مطابقة الأنماط (pattern matching) داخل <code dir=\"ltr\">switch</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">func</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> label</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> method: PaymentMethod) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    switch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> method {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .cash</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Cash\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> lastFour)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Card ending </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">lastFour</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">transfer</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> bank, </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> reference</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">bank</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> transfer, ref </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">reference</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">transfer</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> bank, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">nil</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">bank</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> transfer\"</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">label</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: groceries)   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// \"Card ending 4242\"</span></span></code></pre></div>\n<p>تربط <code dir=\"ltr\">let lastFour</code> القيمة المرتبطة بثابت جديد داخل تلك الحالة. وحالتا <code dir=\"ltr\">.transfer</code> تُظهران إلى أي مدى تصل الأنماط: <code dir=\"ltr\">let reference?</code> لا تطابق إلا حين يكون للمرجع الاختياري قيمة، وتفكّه، و<code dir=\"ltr\">nil</code> تطابق حين لا تكون له قيمة. وما زال الـ compiler يتحقّق من أن الحالتين معًا تغطّيان كل الاحتمالات.</p>\n<p>حين تهمّك حالة واحدة فقط، تكون <code dir=\"ltr\">if case</code> أقصر من switch كاملة:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">if</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> lastFour) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> groceries {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Remind me to check card </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">lastFour</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<aside class=\"callout callout-note\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 16v-4\"/><path d=\"M12 8h.01\"/></svg><span><span class=\"callout-kind\">ملاحظة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>أنت تستخدم enum منذ الدرس الثاني</span></p>\n<p><code dir=\"ltr\">Optional</code> هو enum له حالتان، <code dir=\"ltr\">.some(Wrapped)</code> و<code dir=\"ltr\">.none</code>، و<code dir=\"ltr\">nil</code> اختصار لـ <code dir=\"ltr\">.none</code>. كل <code dir=\"ltr\">if let</code> كتبتها هي مطابقة أنماط على enum له قيمة مرتبطة.</p>\n</aside>\n<h2 id=\"sec-5\" tabindex=\"-1\">enums بدل فوضى القيم المنطقية</h2>\n<p>الـ enums هي الأداة الصحيحة كلما كانت القيمة «واحدة بالضبط من هذه». المثال الكلاسيكي هو تحميل البيانات. المسوّدة الأولى تبدو عادةً كثلاث خصائص منفصلة: <code dir=\"ltr\">isLoading</code> و<code dir=\"ltr\">rates</code> و<code dir=\"ltr\">errorMessage</code>. لا شيء يمنع أن تُضبط الثلاث معًا، فتضطر كل شاشة إلى تخمين أيّها يفوز. enum واحد يُلغي التخمين:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">enum</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> LoadState</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> idle</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> loading</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> loaded</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">([</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal])</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> failed</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>صارت الأسعار موجودة فقط في الحالة <code dir=\"ltr\">.loaded</code>، والرسالة فقط في <code dir=\"ltr\">.failed</code>، وتعالج <code dir=\"ltr\">switch</code> واحدة في الـ view كل حالة مرة واحدة. ستبني هذا بالضبط حين يبدأ Pocket Budget بجلب أسعار الصرف. استخدم enum كلما وجدت نفسك تقارن نصوصًا أو تتلاعب بقيم منطقية لا يجب أن تكون صحيحة معًا أبدًا.</p>\n<p>صارت أنواعك الآن قادرة على وصف بيانات Pocket Budget بدقة. بعد ذلك ستمنحها قدرات مشتركة عبر الـ protocols، مثل «قابل للمقارنة» أو «له معرّف ثابت»، وتضيف سلوكًا إلى أنواع موجودة عبر الـ extensions.</p>\n","toc":[{"id":"sec-1","text":"الـ enums ذات القيم الخام","level":2},{"id":"sec-2","text":"جمل switch الشاملة ميزة","level":2},{"id":"sec-3","text":"القيم المرتبطة: حالات تحمل بيانات","level":2},{"id":"sec-4","text":"استخراج البيانات من جديد","level":2},{"id":"sec-5","text":"enums بدل فوضى القيم المنطقية","level":2}],"takeaways":["الـ enum يسرد كل القيم الصالحة لنوع ما، فيتحوّل خطأ إملائي مثل “Fod” إلى خطأ ترجمة بدل أن يكون خطأً صامتًا.","القيم الخام (<code dir=\"ltr\">enum Category: String</code>) تعطي كل حالة نصًا أو رقمًا مخزّنًا للحفظ وفكّ الترميز.","القيم المرتبطة تُرفق بيانات مختلفة بحالات مختلفة، مثل آخر أربعة أرقام في <code dir=\"ltr\">.card</code>.","اكتب جمل switch على الـ enums بلا <code dir=\"ltr\">default</code>، فإضافة حالة جديدة تجعل الـ compiler يسرد كل switch يجب أن تحدّثها."],"further":[{"title":"Enumerations","url":"https://docs.swift.org/swift-book/documentation/the-swift-programming-language/enumerations/"},{"title":"CaseIterable","url":"https://developer.apple.com/documentation/swift/caseiterable"}],"quiz":[{"q":"<p>لديك <code dir=\"ltr\">enum Category: String { case food, transport }</code>. ماذا تعيد <code dir=\"ltr\">Category(rawValue: &quot;Food&quot;)</code>؟</p>","options":[{"text":"<code dir=\"ltr\">.food</code>، لأن مطابقة القيم الخام تتجاهل حالة الأحرف.","why":"مطابقة القيم الخام دقيقة حرفيًا. القيمة الخام للحالة food هي “food” بأحرف صغيرة."},{"text":"يتعطّل التطبيق، لأن “Food” ليست قيمة خام صالحة.","why":"المُهيِّئ القابل للفشل موجود تحديدًا لتجنّب التعطّل عند المدخلات السيئة."},{"text":"<code dir=\"ltr\">nil</code>","why":"صحيح. <code dir=\"ltr\">init(rawValue:)</code> قابل للفشل ويعيد <code dir=\"ltr\">Category?</code>؛ و&quot;Food&quot; لا تطابق “food”."}],"answer":2},{"q":"<p>أضفت <code dir=\"ltr\">case gifts</code> إلى <code dir=\"ltr\">Category</code>. كل جملة <code dir=\"ltr\">switch</code> على <code dir=\"ltr\">Category</code> تستخدم حالات صريحة دون <code dir=\"ltr\">default</code>. ماذا يحدث في الترجمة التالية؟</p>","options":[{"text":"يُبلغ الـ compiler عن كل switch لا تعالج <code dir=\"ltr\">.gifts</code>.","why":"صحيح. فحص الشمول يحوّل مهمة «اعثر على كل مكان يحتاج تحديثًا» إلى قائمة أخطاء."},{"text":"تنجح الترجمة، وتقع <code dir=\"ltr\">.gifts</code> في آخر حالة وقت التشغيل.","why":"لا توجّه Swift أبدًا حالة غير معالَجة إلى أي مكان بصمت."},{"text":"تنجح الترجمة، ويتعطّل التطبيق حين يصادف <code dir=\"ltr\">.gifts</code>.","why":"بدون <code dir=\"ltr\">default</code>، تُكتشف الفجوة وقت الترجمة، لا وقت التشغيل."}],"answer":0},{"q":"<p>أيّ تعريف يصف «مدفوع بالبطاقة، ونعرف آخر أربعة أرقام منها»؟</p>","options":[{"text":"<code dir=\"ltr\">case card = &quot;4242&quot;</code>","why":"القيمة الخام ثابتة للحالة؛ فكل دفعة بالبطاقة ستنتهي بـ 4242."},{"text":"<code dir=\"ltr\">case card(lastFour: String)</code>","why":"صحيح. القيمة المرتبطة تُخزَّن لكل instance، فتحمل كل دفعة أرقامها الخاصة."},{"text":"<code dir=\"ltr\">case card; var lastFour: String</code>","why":"الـ enums لا يمكن أن تحتوي خصائص مخزّنة للـ instance؛ والقيم المرتبطة هي طريقة الحالات لحمل البيانات."},{"text":"<code dir=\"ltr\">case card(String) = &quot;card&quot;</code>","why":"لا تسمح Swift بالقيم الخام في enum لحالاته قيم مرتبطة."}],"answer":1}],"exercise":{"kind":"fill","language":"swift","template":"enum Category: String, {{0}} {\n    case food, transport, fun\n}\nprint(Category.{{1}}.count)   // 3\n\nenum PaymentMethod {\n    case cash\n    case card(lastFour: String)\n}\n\nfunc label(for method: PaymentMethod) -> String {\n    switch method {\n    case .cash:\n        return \"Cash\"\n    case .card({{2}} lastFour):\n        return \"Card ending \\(lastFour)\"\n    }\n}","blanks":[{"answers":["CaseIterable"]},{"answers":["allCases"]},{"answers":["let"]}],"title":"صمّم التصنيفات وطرق الدفع","prompt":"<p>أكمل الـ enums الاثنين في Pocket Budget. يجب أن يوفّر <code dir=\"ltr\">Category</code> قائمة بكل حالاته حتى يعرضها المنتقي، ويجب أن تقرأ <code dir=\"ltr\">label(for:)</code> آخر أربعة أرقام من الدفع بالبطاقة.</p>\n","hints":["الـ protocol الذي يولّد قائمة بكل الحالات في اسمه كلمة “Case”.","القائمة المولّدة خاصية static: <code dir=\"ltr\">Category.____</code>.","داخل نمط <code dir=\"ltr\">case</code>، الكلمة المفتاحية التي تربط القيمة المرتبطة بثابت جديد هي نفسها التي تعرّف بها الثوابت."],"explanation":"<p>يجعل <code dir=\"ltr\">CaseIterable</code> الـ compiler يولّد <code dir=\"ltr\">Category.allCases</code>، وهي مصفوفة بكل الحالات بترتيب تعريفها، فتكون <code dir=\"ltr\">count</code> مساوية لـ 3. وفي الـ switch، تطابق <code dir=\"ltr\">case .card(let lastFour)</code> الدفعات بالبطاقة وتربط القيمة المرتبطة بالثابت <code dir=\"ltr\">lastFour</code> داخل ذلك الفرع.</p>\n<p>لاحظ أن الـ switch بلا <code dir=\"ltr\">default</code>. إن أضفت <code dir=\"ltr\">case transfer(bank: String)</code> لاحقًا، ستتوقّف هذه الدالة عن الترجمة حتى تعالج الحالة الجديدة، وهذا بالضبط ما تريده.</p>\n","checkLabels":{}},"words":611,"readMinutes":4}