Result Builder هي سمة Swift تُنفذ عبر البروتوكول @resultBuilder الذي يحول تسلسل التعبيرات إلى قيمة مركبة. يقوم المترجم بتحويل كتل التعليمات البرمجية مع تراكيب التحكم if، for، switch إلى استدعاءات لطرق ثابتة للباني — buildBlock، buildEither، buildArray. وفقاً لاقتراح Swift Evolution SE-0289 (2022)، تسمح result builders بإنشاء DSL تصريحي داخل Swift بدون محللات خارجية. المثال الأكثر شهرة هو @ViewBuilder في SwiftUI، حيث يتم بناء جسم العرض من عناصر شرطية ودورية بأسلوب تصريحي.
الخلاصة
TupleViewif/else، switch، for-in عبر الطرق buildOptional، buildEither، buildArrayResult Builder (المعروف سابقاً باسم function builders) هي آلية Swift تسمح بتحويل تسلسل من التعبيرات المفصولة بفواصل أسطر إلى قيمة واحدة. يتم الإعلان عنها باستخدام السمة @resultBuilder المطبقة على هيكل ينفذ طرق تحويل ثابتة.
قبل result builders، كانت البنية التصريحية لجسم SwiftUI مستحيلة. بدلاً من قائمة مضغوطة من عناصر العرض، كان على المطورين كتابة استدعاءات TupleView يدوياً. يقوم Result Builder تلقائياً بتغليف كل تعبير، ويدعم التفرع والحلقات، مخفياً تعقيد التركيب عن المطور.
وفقاً لـ Swift Evolution SE-0289، المقبول في 2022، فإن result builder هو تطور لفكرة function builders (SE-0258، Swift 5.1). التغييرات الرئيسية: إعادة التسمية من @_functionBuilder إلى @resultBuilder والتوسيع إلى وسائط الدوال، مما يسمح باستخدام البنائين لأي وسائط إغلاق، وليس فقط أجسام العرض.
استخدم result builders عندما تحتاج إلى تزويد مستخدمي مكتبتك ببنية تصريحية لبناء هياكل معقدة — تكوينات، استعلامات، مكونات واجهة مستخدم — دون كتابة كود تجميع أمري.
يقوم مترجم Swift بتحويل كل كتلة تعليمات برمجية موسومة بـ @resultBuilder إلى تسلسل من استدعاءات الطرق الثابتة للباني. لنلق نظرة على باني بسيط يدمج السلاسل النصية:
@resultBuilder
struct StringBuilder {
static func buildBlock(_ parts: String...) -> String {
parts.joined(separator: " ")
}
}
استخدام هذا الباني — كل سلسلة في سطر منفصل تُدمج بمسافة:
@StringBuilder
func greeting() -> String {
"Hello"
"World"
"from"
"Swift"
}
// يُحوّل المترجم هذا إلى:
// StringBuilder.buildBlock("Hello", "World", "from", "Swift")
// النتيجة: "Hello World from Swift"
يقوم المترجم بتجميع التعبيرات المتتالية ويمررها كوسائط متغيرة إلى buildBlock. إذا ظهر if بين التعبيرات، يستدعي المترجم buildOptional أو buildEither للتفرع. للحلقات for-in يستدعي buildArray. وهكذا، يتحول كود Swift العادي إلى سلسلة من الاستدعاءات التي تبني القيمة النهائية.
يحدد كل result builder مجموعة من الطرق الثابتة التي يستدعيها المترجم أثناء التحويل. الطرق الرئيسية:
| الطريقة | الغرض | متى تُستدعى |
|---|---|---|
| buildBlock | يدمج تسلسل التعبيرات | لكل كتلة بدون تفرع |
| buildOptional | يعالج if بدون else | عند وجود if بدون else |
| buildEither(first:) | الفرع الأول من if-else | عند if مع else |
| buildEither(second:) | الفرع الثاني من if-else | عند if مع else |
| buildArray | يعالج حلقات for-in | عند وجود for-in |
| buildExpression | يحول التعبيرات الفردية | لكل تعبير قبل تمريره إلى buildBlock |
| buildFinalResult | التحويل النهائي | قبل العودة من الإغلاق |
يتطلب الحد الأدنى من التنفيذ فقط buildBlock مع وسائط متغيرة — وهذا كافٍ للكتل بدون تفرع. إضافة buildOptional و buildEither يتضمن دعم التراكيب الشرطية، و buildArray يتضمن الحلقات. وفقاً لوثائق Swift (2025)، يُوصى بتنفيذ جميع الطرق لتحقيق أقصى مرونة لـ DSL.
buildExpression يسمح بقبول تعبيرات من أنواع مختلفة وتحويلها إلى نوع واحد للباني. على سبيل المثال، في @ViewBuilder، buildExpression يقبل Text، Image، Button ويحولها إلى النوع المشترك View.
لنلق نظرة على إنشاء باني لبناء سلاسل HTML. سيسمح هذا DSL بكتابة HTML تصريحي مباشرة في Swift:
@resultBuilder
enum HTMLBuilder {
static func buildBlock(_ components: String...) -> String {
components.joined()
}
static func buildOptional(_ component: String?) -> String {
component ?? ""
}
static func buildEither(first component: String) -> String {
component
}
static func buildEither(second component: String) -> String {
component
}
static func buildArray(_ components: [String]) -> String {
components.joined()
}
}
استخدام الباني المخصص لتوليد HTML:
func div(@HTMLBuilder _ content: () -> String) -> String {
"<div>\(content())</div>"
}
func p(_ text: String) -> String {
"<p>\(text)</p>"
}
let page = div {
p("Hello")
p("World")
if showFooter {
p("تذييل")
}
}
// النتيجة: <div><p>Hello</p><p>World</p><p>Footer</p></div>
وفقاً لمقال “Building Custom Result Builders in Swift” من Swift.org (2025)، تُستخدم البنائين المخصصين في المكتبات لبناء ملفات التكوين، مكونات واجهة المستخدم، تعيين البيانات، وحتى استعلامات قاعدة البيانات — في أي مكان نحتاج فيه إلى بنية تصريحية مع دعم التفرع.
@ViewBuilder هو result builder مدمج في SwiftUI يُطبق على وسيطة content لمعظم عناصر العرض الحاوية: VStack، HStack، ZStack، Group، List، والخاصية body نفسها. يسمح بكتابة عدة عناصر عرض في أسطر منفصلة بدون فواصل أو أغلفة.
@ViewBuilder ينفذ جميع طرق result builder، بما في ذلك دعم if-else، switch، و for-in. عندما يتحقق الشرط، يُرجع buildEither(first:) عرضاً واحداً؛ عندما لا يتحقق، يُرجع buildEither(second:) عرضاً آخر. يجب أن يُرجع كلا الفرعين نفس النوع، لكن SwiftUI يستخدم AnyView داخلياً أو محو النوع عبر ConditionalContent.
struct GreetingView: View {
let isLoggedIn: Bool
var body: some View {
VStack {
Image(systemName: "person.circle")
Text("الملف الشخصي")
.font(.title)
if isLoggedIn {
Text("مرحبًا بعودتك!")
.foregroundColor(.green)
} else {
Button("تسجيل الدخول") { }
}
}
}
}
بدون @ViewBuilder، كان نفس الكود سيتطلب Group لكل قسم شرطي أو استخدام AnyView، مما يضر بالأداء. @ViewBuilder يختار تلقائياً التمثيل الأكثر كفاءة — ConditionalContent أو TupleView — لكل مجموعة.
أول قيد هو العدد الأقصى للتعبيرات في buildBlock. تحدد مكتبة Swift القياسية تحميلات buildBlock لـ 2–10 تعابير. إذا كان في الكتلة أكثر من 10 تعابير، سيصدر المترجم خطأ. الحل هو التجميع عبر Group أو VStack لتقسيمها إلى كتل فرعية.
القيد الثاني هو عدم وجود دعم للمتغيرات والتعيينات داخل كتلة الباني. لا يمكنك تعريف let x = 5 داخل @ViewBuilder. يجب أن تكون كل التعبيرات تعابير تُرجع قيمة من نوع الباني. للحسابات الوسيطة، استخدم حسابات خارج الباني أو buildExpression مع دعم لأنواع مختلفة.
القيد الثالث هو تعقيد التصحيح. غالباً ما تنتج أخطاء الترجمة داخل result builder رسائل مربكة، خاصةً عندما لا تتطابق الأنواع في فروع if/else. استخدم أنواع إرجاع صريحة و AnyView للتصحيح، على الرغم من أن الأخير يقلل الأداء. وفقاً لـ Hacking with Swift (2025)، نصيحة عملية — ابدأ بباني بسيط بدون تفرع وأضف دعم التراكيب الشرطية تدريجياً.
الأسئلة الشائعة
Result Builder هي سمة Swift تحول تسلسل التعبيرات إلى قيمة ناتجة عبر طرق ثابتة. تسمح بإنشاء DSL تصريحي، المثال الأكثر شهرة هو @ViewBuilder في SwiftUI لبناء تسلسل هرمي للعرض بدون كود أمري.
صرّح عن هيكل بالسمة @resultBuilder ونفذ على الأقل طريقة buildBlock. لدعم الشروط، أضف buildOptional و buildEither؛ للحلقات، أضف buildArray. استخدم سمة الباني قبل وسيطة الإغلاق في دالة.
فقط buildBlock إلزامي. جميع الطرق الأخرى — buildOptional، buildEither، buildArray، buildExpression، buildFinalResult — اختيارية وتضيف دعم التراكيب المقابلة. كلما زاد عدد الطرق المنفذة، زادت مرونة DSL.
@ViewBuilder هو تطبيق ملموس لـ result builder لبروتوكول View. تم تعريفه في SwiftUI كهيكل بالسمة @resultBuilder، يوفر طرق buildBlock لعدد مختلف من عناصر العرض (TupleView)، buildEither لـ ConditionalContent و buildArray لـ ForEach.
نعم، تحميلات buildBlock القياسية تدعم حتى 10 تعابير. عند تجاوز ذلك، استخدم حاويات متداخلة (Group، VStack) للتقسيم إلى كتل فرعية. يمكن لباني مخصص تعريف buildBlock متغير بدون حد.
الملخص
buildBlock، buildEither، buildOptional، buildArray حسب تراكيب التحكمسنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.