Result Builder — یک ویژگی Swift است که از طریق پروتکل @resultBuilder پیادهسازی میشود و تسلسل عبارات را به یک مقدار ترکیبی تبدیل میکند. کامپایلر بلوکهای کد با ساختارهای کنترلی if، for، switch را به فراخوانیهای روشهای ساکن بیلدر — buildBlock، buildEither، buildArray — تبدیل میکند. بر اساس Swift Evolution پیشنهاد SE-0289 (2022)، result builderها اجازه ایجاد DSLهای تصریحی در داخل Swift بدون تجزیهگرهای خارجی را میدهند. معروفترین مثال — @ViewBuilder در SwiftUI، جایی که بدنه view از عناصر شرطی و حلقهای به سبک تصریحی ساخته میشود.
نکات کلیدی
TupleView تبدیل میکندif/else، switch، for-in از طریق روشهای buildOptional، buildEither، buildArray پشتیبانی میکندResult Builder (قبلاً به عنوان function builders شناخته میشد) — مکانیزم Swift است که به شما اجازه میدهد تسلسل عبارات جداشده شده با خط جدید را به یک مقدار واحد تبدیل کنید. با استفاده از ویژگی @resultBuilder اعلام میشود که بر ساختاری اعمال میگردد که روشهای استاتیک تبدیل را پیادهسازی میکند.
قبل از ظهور result builderها، نحوه نگارش تصریحی SwiftUI body ممکن نبود. به جای یک لیست مختصر از viewها، برنامهنویس مجبور بود به صورت دستی فراخوانیهای TupleView را بنویسد. Result Builder به طور خودکار هر عبارت را میپیچد، شاخه و حلقه را پشتیبانی میکند و پیچیدگی ترکیب را از برنامهنویس پنهان میکند.
بر اساس Swift Evolution SE-0289 که در سال 2022 پذیرفته شد، result builder تکامل ایده function builders (SE-0258، Swift 5.1) است. تغییرات اصلی: تغییر نام از @_functionBuilder به @resultBuilder و گسترش به پارامترهای تابع، که اجازه استفاده از builderها را برای هر آرگومان closure داد، نه فقط برای بدنه view.
هر زمان که میخواهید به کاربران کتابخانه خود نحوه نگارش تصریحی برای ساخت ساختارهای پیچیده — پیکربندیها، پرسوجوها، کامپوننتهای UI — بدون نوشتن کد ساخت امری ارائه دهید، از result builderها استفاده کنید.
کامپایلر Swift هر بلوک کد علامتگذاری شده با @resultBuilder را به یک تسلسل از فراخوانی روشهای استاتیک بیلدر تبدیل میکند. سادهترین builder را که رشتهها را به هم میپیوند، در نظر بگیرید:
@resultBuilder
struct StringBuilder {
static func buildBlock(_ parts: String...) -> String {
parts.joined(separator: " ")
}
}
استفاده از این builder — هر خط در یک رشته جداگانه با یک فاصله به هم میپیوند:
@StringBuilder
func greeting() -> String {
"Hello"
"World"
"from"
"Swift"
}
// کامپایلر این را به این شکل تبدیل میکند:
// StringBuilder.buildBlock("Hello", "World", "from", "Swift")
// نتیجه: "Hello World from Swift"
کامپایلر عبارات متوالی را گروهبندی کرده و آنها را به عنوان پارامتر variadic به 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 | تبدیل نهایی | قبل از بازگشت از closure |
پیادهسازی حداقل فقط buildBlock با پارامترهای variadic را نیاز دارد — این برای بلوکهای بدون شاخه کافی است. افزودن buildOptional و buildEither پشتیبانی از ساختارهای شرطی را فعال میکند و buildArray — حلقهها. بر اساس Swift Documentation (2025)، پیادهسازی تمام روشها برای حداکثر انعطافپذیری DSL توصیه میشود.
buildExpression به شما اجازه میدهد عبارات از انواع مختلف را بپذیرید و آنها را به نوع واحد builder تبدیل کنید. مثالاً، در @ViewBuilder، buildExpression عباراتی از نوع Text، Image، Button را پذیرفته و آنها را به نوع مشترک View تبدیل میکند.
ایجاد یک builder برای ساخت رشتههای 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()
}
}
استفاده از builder سفارشی برای تولید 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)، builderهای سفارشی در کتابخانهها برای ساخت فایلهای پیکربندی، کامپوننتهای UI، نقشه خوانی دادهها و حتی پرسوجوهای پایگاه داده استفاده میشوند — هر جایی که نحوه نگارش تصریحی با پشتیبانی از شاخه نیاز است.
@ViewBuilder — یک result builder ساخته شده در SwiftUI است که به پارامتر content اکثر کانتینرها اعمال میشود: VStack، HStack، ZStack، Group، List و خود ویژگی body. این امکان نوشتن چندین view در رشتههای جداگانه بدون کاما و پیچونده ها را فراهم میکند.
@ViewBuilder تمام روشهای result builder را از جمله پشتیبانی از if-else، switch و for-in پیاده میکند. وقتی شرط برقرار است، buildEither(first:) یک view را برمیگرداند؛ وقتی نیست — buildEither(second:) view دیگری را. هر دو شاخه باید همان نوع را بازگردانند، اما 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 برای 2–10 عبارت برای buildBlock سابرولود تعریف میکند. اگر در بلوک بیش از 10 عبارت وجود داشته باشد، کامپایلر خطا میدهد. راه حل — جداسازی به زیربلوکها با استفاده از Group یا VStack.
محدودیت دوم — نبود پشتیبانی از متغیرها و تعیین مقادیر داخل بلوک builder. نمیتوان let x = 5 را داخل @ViewBuilder اعلام کرد. همه عبارات باید عباراتی باشند که مقدار نوع builder را بازگردانند. برای محاسبات وسیط، از محاسبات خارج از builder یا buildExpression با پشتیبانی از انواع مختلف استفاده کنید.
محدودیت سوم — دشواری دباگ. خطاهای کامپایل داخل result builder اغلب پیامهای گنجده میدهند، به ویژه در ناهماهنگی انواع در شاخههای if/else. برای دباگ از انواع صریح بازگشتی و AnyView استفاده کنید، هر چند آخری عملکرد را کاهش میدهد. به استناد به Hacking with Swift (2025)، توصیه عملی — با یک builder ساده بدون شاخه شروع کرده و پشتیبانی از ساختارهای شرطی را تدریجاً اضافه کنید.
سوالات متداول
Result Builder — ویژگی Swift است که تسلسل عبارات را از طریق روشهای استاتیک به مقدار نهایی تبدیل میکند. امکان ایجاد DSLهای تصریحی را فراهم میکند، معروفترین مثال — @ViewBuilder در SwiftUI برای ساخت سلسله مراتب view بدون کد امری.
یک ساختار با ویژگی @resultBuilder اعلام کرده و حداقل روش buildBlock را پیاده کنید. برای پشتیبانی از شرایط، buildOptional و buildEither را اضافه کرده، برای حلقهها — buildArray. از ویژگی builder قبل پارامتر closure در تابع استفاده کنید.
فقط buildBlock اجباری است. سایر روشها — buildOptional، buildEither، buildArray، buildExpression، buildFinalResult — اختیاری هستند و پشتیبانی از ساختارهای مربوطه را اضافه میکنند. هر چه روشهای بیشتری پیاده شوند، DSL انعطافپذیرتر خواهد بود.
@ViewBuilder — پیادهسازی مشخصی از result builder برای پروتکل View است. در SwiftUI به عنوان ساختاری با ویژگی @resultBuilder تعریف شده است که روش buildBlock را برای تعداد مختلف view (TupleView)، buildEither را برای ConditionalContent و buildArray را برای ForEach فراهم میکند.
بله، سابرولودهای استاندارد buildBlock تا 10 عبارت را پشتیبانی میکنند. در صورت تجاوز، از کانتینرهای تودرتو (Group، VStack) برای تقسیم به زیربلوکها استفاده کنید. یک builder سفارشی میتواند buildBlock بدون محدودیت با variadic تعریف کند.
خلاصه
buildBlock، buildEither، buildOptional، buildArray بسته به ساختارهای کنترلی جایگزین میکندما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید