@Binding یک Property Wrapper در SwiftUI است که ارجاعی به دادههای متعلق به مؤلفه دیگر ایجاد میکند. Binding مقدار را به طور مستقل ذخیره نمیکند — فقط از طریق پروجکشن $ به منبع حقیقت موجود دسترسی فراهم میکند. طبق Apple Developer Documentation (2025)، Binding یک ارتباط دوطرفه واکنشی بین نمای والد و فرزند بدون مالکیت مستقیم دادهها فراهم میکند. @Binding مکانیسم کلیدی برای انتقال حالت تغییرپذیر به پایین سلسلهمراتب است.
نکات اصلی
@Binding یک Property Wrapper است که یک ارتباط دوطرفه بین ویژگی ذخیرهشده در نمای والد و مؤلفه فرزند ایجاد میکند. تفاوت اصلی Binding با @State: Binding صاحب داده نیست. آن فقط مقدار را از طریق منبع واقعی — @State، @StateObject یا Binding دیگر در والد — میخواند و مینویسد. بدون Binding، نماهای فرزند نمیتوانستند حالت اجداد را بدون callback یا delegate تغییر دهند.
Binding به عنوان یک ساختار با دو ویژگی پیادهسازی شده است: wrappedValue (مقدار فعلی) و projectedValue (خود Binding که از طریق $ قابل دسترسی است). وقتی نمای فرزند wrappedValue را از طریق Binding تغییر میدهد، SwiftUI تغییر را به منبع داده منتقل کرده و همه نماهای وابسته را دوباره ترسیم میکند. این به صورت همزمان در چرخه بهروزرسانی فعلی رخ میدهد.
ویژگی مهم: @Binding به انتقال تکسطحی محدود نمیشود. Binding را میتوان از طریق چندین سطح سلسلهمراتب منتقل کرد — هر مؤلفه فرزند به یک منبع داده یکسان ارجاع دریافت میکند. تغییر در هر سطحی باعث بهروزرسانی واحد همه نماهای مرتبط میشود.
مکانیسم ارتباط دوطرفه از طریق @Binding بر روی پروجکشن Property Wrapperها ساخته شده است. وقتی والد @State var value: T را اعلان میکند، SwiftUI به طور خودکار پروجکشن $value از نوع Binding
struct SliderContainer: View {
@State private var value: Double = 0.5
var body: some View {
VStack {
Text("مقدار: \(value)")
SliderView(value: $value)
}
}
}
struct SliderView: View {
@Binding var value: Double
var body: some View {
Slider(value: $value, in: 0...1)
}
}
در مثال SliderContainer صاحب @State value است و SliderView Binding را از طریق $value دریافت میکند. Slider داخل SliderView به این Binding متصل است. هنگام کشیدن لغزنده، Slider مقدار را از طریق Binding تغییر میدهد که به طور خودکار @State را در SliderContainer بهروزرسانی کرده و هر دو نما عدد فعلی را نمایش میدهند. کل زنجیره بدون هیچ callback یا اعلانی کار میکند.
برای ایجاد Binding از @StateObject یا @ObservedObject از همان پروجکشن استفاده میشود: $object.property یک Binding
قبل از SwiftUI روش استاندارد انتقال تغییرات به بالای سلسلهمراتب callbackها و delegateها بود: والد یک closure ارسال میکرد، مؤلفه فرزند آن را هنگام تغییر فراخوانی میکرد. @Binding جایگزینی با کد کمتر و نحو اعلانیتر ارائه میدهد. به جای ارسال closure تکمیلی، کافی است $stateValue را ارسال کنید.
| معیار | @Binding | Callbackها |
|---|---|---|
| کد | یک حاشیهنویس + $ | Closure + فراخوانی |
| چندسطحی | خودکار | زنجیره closureها |
| تست | Binding(value:constant) | Mock-closureها |
| خوانایی | بالا | متوسط |
| انعطافپذیری | فقط داده | هر منطقی |
زمانی از @Binding استفاده کنید که نمای فرزند فقط نیاز به خواندن و تغییر مقدار دارد. اگر انجام اقدامات جانبی در زمان تغییر (اعتبارسنجی، ثبت رویداد، درخواست شبکه) مورد نیاز است، Binding را با callback ترکیب کنید: Binding را برای داده و closure را برای رویدادها ارسال کنید. برای مثال، TextField میتواند به Binding متصل شود و onChange اعتبارسنجی را اجرا کند.
@Binding در چند سناریوی معمولی استفاده میشود. اول — کنترلهای سفارشی: سوئیچها، لغزندهها، انتخابگرهای رنگ و سایر عناصر تعاملی برای همگامسازی دوطرفه Binding دریافت میکنند. دوم — پنجرههای مودال: پرچم نمایش sheet به عنوان Binding منتقل میشود و به نمای فرزند اجازه میدهد خود را از طریق presentationMode یا تنظیم مستقیم ببندد.
الگوی سوم — فرمهای تقسیمشده. اگر فرم از فیلدهای متعددی تشکیل شده باشد، هر فیلد را میتوان به یک مؤلفه جداگانه منتقل کرد که Binding را برای مقدار خود دریافت میکند. این کار تست و استفاده مجدد فیلدها را بین فرمهای مختلف ساده میکند. مؤلفه والد تنها صاحب کل مدل فرم باقی میماند.
struct FormField: View {
let title: String
@Binding var text: String
var body: some View {
VStack(alignment: .leading) {
Text(title).font(.caption)
TextField("Enter \(title.lowercased())", text: $text)
.textFieldStyle(.roundedBorder)
}
}
}
مؤلفه FormField عنوان و Binding به یک رشته را دریافت میکند. آن برچسب و TextField متصل به Binding منتقلشده را نمایش میدهد. هر فرمی میتواند با ارسال $property برای هر فیلد، چندین بار از FormField استفاده کند. این کار تکرار نشانهگذاری را کاهش داده و استایلدهی فیلدهای متنی را متمرکز میکند.
SwiftUI امکان ایجاد دستی Binding را از طریق مقداردهنده Binding(get:set:) فراهم میکند. این زمانی مفید است که نیاز به افزودن منطق هنگام خواندن یا نوشتن مقدار دارید. برای مثال، میتوان Bindingای ایجاد کرد که عدد را قبل از ذخیره فرمت میکند، یا Bindingای که مقدار را با هر تغییر با سرور راه دور همگام میکند.
struct ValidatedField: View {
@State private var email: String = ""
var emailBinding: Binding<String> {
.init(
get: { email },
set: { email = $0.lowercased().trimmingCharacters(in: .whitespaces) }
)
}
var body: some View {
TextField("Email", text: emailBinding)
}
}
در لیستینگ، emailBinding سفارشی به طور خودکار متن را به حروف کوچک تبدیل کرده و فاصلهها را در هر تغییر حذف میکند. TextField به جای اتصال مستقیم به $email از این Binding استفاده میکند. چنین رویکردی امکان متمرکز کردن اعتبارسنجی و تبدیل دادهها در داخل Binding را بدون آلوده کردن کد با کنترلکنندههای onChange فراهم میکند.
اولین و رایجترین خطا — انتقال مقدار به جای Binding. اگر مؤلفه فرزند @Binding var text: String را اعلان کند و والد text (بدون $) را ارسال کند، کامپایلر خطا میدهد: Cannot convert value of type 'String' to expected argument type 'Binding
دومین خطا — Binding روی دادههای فقط خواندنی. اگر نمای فرزند فقط نیاز به خواندن مقدار دارد، از @Binding استفاده نکنید — let ساده یا @State از والد کافی است. Binding امکان نوشتن را فرض میکند و حقوق اضافی تغییر، اشکالزدایی را پیچیده کرده و اصل حداقل دسترسی را نقض میکند.
سومین مشکل — Binding.constant در تولید. Binding.constant(value) یک اتصال ساختگی بدون بازخورد ایجاد میکند — تغییرات نادیده گرفته میشوند. constant را فقط برای نمونهسازی اولیه و پیشنمایشها (Xcode Previews) استفاده کنید، اما هرگز در کد واقعی. برای تستها از Binding(get:set:) با رفتار کنترلشده استفاده کنید.
سوالات متداول
@State مالک دادههاست و ذخیرهسازی آنها را در heap مدیریت میکند. @Binding فقط به حالت موجود بدون مالکیت ارجاع میدهد. @State همیشه private است، @Binding — پارامتر ورودی نمای فرزند.
بله، از طریق مقداردهنده Binding(get:set:) یا Binding.constant(value). همچنین Binding را میتوان از @StateObject از طریق پروجکشن $object.$property و از Publisher از طریق Binding(get:set:) داخل Subscribe دریافت کرد.
@Binding در طول زنجیره منتقل میشود: هر مؤلفه میانی @Binding را اعلان کرده و آن را از طریق $ به پایین منتقل میکند. همه سطوح به یک منبع داده در نمای ریشه ارجاع میدهند.
Binding.constant یک پوشش بیصدا ایجاد میکند — setter مقادیر جدید را نادیده میگیرد. این فقط برای نمونهسازی اولیه و SwiftUI Previews طراحی شده است، جایی که بازخورد از مؤلفه فرزند مورد نیاز نیست.
بله، Binding<T?> پشتیبانی میشود. اگر Binding<String?> را ارسال کنید، نمای فرزند میتواند nil تنظیم کند. این برای فیلدهای اختیاری فرم یا حالتهای با امکان بازنشانی مفید است.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید