Mojtaba Mirzadeh
Mojtaba Mirzadeh
خواندن ۵ دقیقه·۱ ماه پیش

بررسی State@ در SwiftUI: راه و روش راحت کنترل وضعیت با یه تیر و دو نشون (هم تغییر، هم نمایش!)

دقیقا State@ در SwiftUi چیست؟

در SwiftUI، وقتی می‌خواهیم داده‌ای داشته باشیم که هر وقت تغییر کند، رابط کاربری (UI) هم بلافاصله تغییر کنه، از یه چیزی به اسم State@ استفاده می‌کنیم. به زبان خیلی ساده، State@ یه روشه که کمک می‌کنه تا داده‌ها درون یک View مدیریت بشن. هر وقت این داده‌ها عوض بشن، SwiftUI می‌فهمه و خود به خود رابط کاربری رو آپدیت می‌کنه تا تغییرات رو ببینیم.

چرا به @State نیاز داریم؟

فرض کن توی SwiftUI یه دکمه داری و می‌خوای هر بار که روی دکمه کلیک می‌کنی، یه عدد زیاد بشه و این عدد رو روی صفحه نمایش بدی. State@ باعث میشه SwiftUI بفهمه وقتی عدد تغییر می‌کنه، باید صفحه رو دوباره رندر کنه و عدد جدید رو نمایش بده. بدون State@، قطعا SwiftUI نمی‌فهمه که داده عوض شده و بنابراین UI هم ثابت می‌مونه.

یه مثال بزنیم که باهاش کاملاً قضیه رو متوجه بشی:

https://gist.github.com/smsdm4/e14a86329ac27343a4a42b3542b0b53d

۱- اینجا ما یه متغیر به نام counter داریم که از نوع State@ هست. یعنی اگه مقدارش تغییر کنه، SwiftUI به طور خودکار صفحه رو آپدیت می‌کنه.

۲- با Text("Counter: \(counter)") مقدار counter رو توی متن نمایش می‌دیم.

۳- دکمه (:Button(action هر بار که روش کلیک بشه، مقدار counter رو یک واحد زیاد می‌کنه. بعدش SwiftUI به‌طور خودکار مقدار جدید رو توی UI نمایش می‌ده.


مثال دیگر: تغییر رنگ پس‌زمینه

حالا بیایید یه مثال دیگه بزنیم که کاربر با کلیک روی دکمه، رنگ پس‌زمینه رو تغییر بده:

https://gist.github.com/smsdm4/c8f01cf5dc86d484832f2196c6b14505

۱- اینجا یه متغیر داریم که میگه پس‌زمینه آبی هست یا نه.

۲- اگه مقدار isBlue (True) باشه، رنگ پس‌زمینه آبی میشه، اگه نه، سبز میشه.

۳- با کلیک روی دکمه، مقدار isBlue عوض میشه و رنگ پس‌زمینه تغییر می‌کنه.


چرا چنین چیزی رو در UIKit نداشتیم؟

توی UIKit، که قبلتر از SwiftUI برای ساخت اپ‌های iOS استفاده می‌شد، چنین چیزی به این راحتی وجود نداشت. توی UIKit، برنامه‌نویس‌ها باید به‌صورت دستی وضعیت داده‌ها و رابط کاربری رو هماهنگ می‌کردن. مثلاً اگه می‌خواستی با یه دکمه یه عدد رو زیاد کنی، باید اول مقدار متغیر رو عوض می‌کردی و بعدش به‌طور دستی به رابط کاربری می‌گفتی که متن رو آپدیت کنه.

مثال ساده توی UIKit این شکلی بود:

https://gist.github.com/smsdm4/0be4aa365078a7547a80dce10bdf9e6a

تو این روش، باید خودت به‌طور مستقیم بگی "آقا، متن برچسب رو عوض کن!" ولی تو SwiftUI با State@ همه چی خودکار انجام می‌شه. SwiftUI خودش می‌فهمه که باید چی کار کنه.

تفاوت اصلی در SwiftUI:

۱- تو SwiftUI وقتی از @State استفاده می‌کنی، داده‌ها و UI همیشه با هم همگام هستن و نیاز نیست هیچ کار اضافه‌ای انجام بدی.

۲- در UIKit اینطوری نبود و باید خودت دستی همه چی رو مدیریت می‌کردی.


نکات تکمیلی درباره State@:

۱- توجه کنید که State@ فقط برای View‌های محلیه: یعنی اگه وضعیت (state) فقط توی یه View تغییر می‌کنه، از State@ استفاده می‌کنی. ولی اگه قرار باشه بین چند View مختلف از یه داده استفاده بشه، باید از چیزای دیگه‌ای مثل Binding@ یا ObservedObject@ استفاده کنی.

۲- محدودیت استفاده در Struct: تو SwiftUI، هاView به‌صورت Struct تعریف می‌شن که نوعشون Immutable یا غیرقابل تغییره. State@ کمک می‌کنه داده‌های متغیر (مانند counter) رو بدون مشکل توی این ساختارها مدیریت کنیم.

۳- چرخه حیات State@: اگه View از صفحه حذف بشه، مقدار State@ هم از دست می‌ره. یعنی اگه مثلاً یه صفحه بره و برگرده، مقدار State@ دوباره از اول شروع می‌شه.

۴- برای مقادیر ساده مناسبه: State@ بیشتر برای چیزای ساده مثل اعداد و رشته‌ها خوبه. اگه وضعیت پیچیده‌تری داری، بهتره از ObservedObject@ استفاده کنی.

۵- بازسازی View: هر وقت مقدار State@ تغییر کنه، SwiftUI کل View رو از نو می‌سازه. این بازسازی می‌تونه رو عملکرد تأثیر بذاره، پس حواست باشه که خیلی پرکاربرد نباشه اگه داده‌های پیچیده داری.

۶- تغییرات در Main Thread: تغییرات در State@ باید روی Main Thread (رشته اصلی) انجام بشه، چون SwiftUI به UI حساسه و همه تغییرات رو باید همون‌جا هندل کنه.
اگه قراره تغییری رو توی پس‌زمینه (Background) انجام بدی، باید از این استفاده کنی:

https://gist.github.com/smsdm4/44ca0ae3db2d2777e16f9849f5bfb85a

۷- استفاده از Binding@ با State@: اگه یه متغیر State@ رو بخوای به یه View دیگه بدی تا اونم تغییرش بده، از Binding@ استفاده می‌کنی.

مثلا:

https://gist.github.com/smsdm4/0fe3a48fc0c3625246cc9b2cbfcc91b5

۸- رابطه State@ و انیمیشن‌ها: تغییرات توی State@ خیلی راحت می‌تونن با انیمیشن همراه بشن. مثلا هر وقت State@ تغییر کنه، SwiftUI خودش انیمیشن اعمال می‌کنه:

https://gist.github.com/smsdm4/b4c129e53f8d19dd9f2579fc8989cbb1

۹- رابطه $ با @State: وقتی در SwiftUI از State@ استفاده می‌کنیم، خود State@ در واقع به ما اجازه می‌ده که مقدار متغیر رو کنترل کنیم. اما وقتی می‌خواهیم این مقدار رو به یه View دیگه یا یک کنترل (مثل Toggle یا Slider) بدیم و اونجا هم اجازه بدیم که تغییرش بدن، باید از یه چیزی به نام Binding استفاده کنیم. اینجا است که علامت $ وارد میشه.

به زبان خیلی ساده: $ کمک می‌کنه که "کنترل دوطرفه" داشته باشیم. یعنی هم بتونی مقدار رو از یک View بگیری و هم از داخل یه View دیگه اونو تغییر بدی.

برای مثال:

فرض کن یه Switch (Toggle) داری و می‌خواهی با کلیک روی اون، یه مقدار بولین (True یا False) رو تغییر بدی. برای این کار باید از $استفاده کنیم تا مقدار ‌Bool با Toggle همگام بشه و اگه کاربر Switch رو تغییر داد، مقدار بولین هم عوض بشه.

https://gist.github.com/smsdm4/496d92138510f8fdd981311d64528207

۱- اینجا یه متغیر به اسم isOn داریم که مشخص می‌کنه آیا Switch روشنه یا خاموش.

۲- اینجا علامت $ می‌گه "من دارم این متغیر رو به صورت Binding به Toggle میدم." یعنی حالا Toggle می‌تونه مستقیماً مقدار isOn رو تغییر بده.

۳- منظور $isOn اینه که به این متغیر اجازه بده از بیرون هم تغییر کنه. اگه فقط isOn رو بدون $ بفرستی، دیگه تغییرات رو نمی‌تونی از داخل Toggle بگیری.



و در نهایت:

  • کلا State@ یه راه ساده و راحت برای مدیریت وضعیت‌های داخلی تو SwiftUI است.
  • هر وقت داده‌ها تغییر کنه، SwiftUI خودش رابط کاربری رو آپدیت می‌کنه.
  • تو UIKit چنین چیزی به این راحتی نداشتیم و باید دستی همه چی رو کنترل می‌کردیم.
  • کلا State@ برای مقادیر ساده خیلی خوبه، ولی اگه وضعیت پیچیده‌تری داری، باید از ابزارهای دیگه‌ای استفاده کنی مثل ObservedObject@.
  • حواست باشه تغییرات State@ باید تو Main Thread انجام بشه و View رو بازسازی می‌کنه.


swiftuiswiftstatebindingرابط کاربری
توسعه‌دهنده ارشد iOS | علاقه‌مند به هوش مصنوعی و یادگیری ماشینی | مدرس برنامه‌نویسی iOS
شاید از این پست‌ها خوشتان بیاید