@StateObject ay isang property wrapper sa SwiftUI na gumagawa at nagmamay-ari ng instance ng ObservableObject sa buong lifecycle ng View. Kapag unang lumitaw ang View sa screen, sinisimulan ng @StateObject ang object at iniimbak ito hanggang sa maalis ang View sa memorya. Ginagarantiyahan nito na hindi ma-reset ang data sa muling pagtatayo ng interface — halimbawa, sa pagpapalit ng tema o pag-update ng parent View. Ayon sa Apple Developer Documentation (2025), dapat gamitin ang @StateObject bilang pangunahing source of truth para sa ObservableObject sa hierarchy ng SwiftUI, habang ang child View ay tumatanggap ng nagawa nang object sa pamamagitan ng @ObservedObject o @EnvironmentObject.
Mga Pangunahing Punto
@StateObject ay isang property wrapper na ipinakilala sa iOS 14 na nagpapahintulot sa View na gumawa at magmay-ari ng instance ng isang klase na sumusunod sa ObservableObject protocol. Hindi tulad ng @State na gumagana sa value types (struct), ang @StateObject ay para sa reference types — mga klase na maaaring mag-notify sa SwiftUI tungkol sa mga pagbabago sa kanilang mga property.
Kapag gumamit ang View ng @StateObject var viewModel: MyViewModel, awtomatikong gumagawa ang SwiftUI ng instance ng MyViewModel sa unang pagpapakita ng View at iniimbak ito sa espesyal na imbakan ng framework. Sa bawat pag-update ng View (halimbawa, sa pagbabago ng parent state), hindi muling ginagawa ng SwiftUI ang object — ginagamit nito ang umiiral na instance hanggang sa maalis ang View mula sa hierarchy.
Ayon sa Apple WWDC Session 10137 (2024), nalulutas ng @StateObject ang problema ng pagkawala ng data sa muling pagtatayo ng View na umiral sa iOS 13, kung kailan kailangang gumawa ng ObservableObject ang mga developer sa parent View at ipasa ito sa pamamagitan ng initializer. Ito ay humantong sa pagdoble ng code at panganib ng hindi sinasadyang muling paggawa ng object.
import SwiftUI
class CounterViewModel: ObservableObject {
@Published var count: Int = 0
func increment() {
count += 1
}
}
struct CounterView: View {
@StateObject var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("Bilang: \(viewModel.count)")
Button("Dagdagan", action: viewModel.increment)
}
}
}
Ang mekanismo ng @StateObject ay batay sa pagsasama ng SwiftUI sa Combine framework. Kapag minarkahan ng ObservableObject ang mga property nito ng @Published attribute, awtomatikong nag-subscribe ang SwiftUI sa mga pagbabago sa pamamagitan ng publisher na naka-embed sa ObservableObject protocol. Kapag nagbago ang isang nai-publish na property, nagpapadala ang object ng signal sa pamamagitan ng objectWillChange publisher, na nagti-trigger ng muling pagguhit ng lahat ng View na nagmamasid sa object na ito.
Iniimbak ng SwiftUI ang instance ng ObservableObject sa isang espesyal na imbakan na nakatali sa isang partikular na instance ng View. Ang imbakan na ito ay ginagawa nang isang beses sa unang render at umiiral hanggang sa pagkasira ng View. Ito ang dahilan kung bakit ginagarantiyahan ng @StateObject ang katatagan ng reference sa object — awtomatikong pinamamahalaan ng SwiftUI ang memorya, nang hindi umaasa sa initializer ng View.
Ayon sa objc.io — Thinking in SwiftUI (2025), ang panloob na implementasyon ng @StateObject ay gumagamit ng mekanismong katulad ng @State, ngunit para sa reference types: gumagawa ang SwiftUI ng boxing wrapper sa paligid ng object at pinamamahalaan ang lifecycle nito sa pamamagitan ng sarili nitong allocator, na na-optimize para sa madalas na muling pagtatayo ng View hierarchy.
Ang pangunahing pagkakaiba sa pagitan ng @StateObject at @ObservedObject ay kung sino ang nagmamay-ari ng object. Ang @StateObject ay gumagawa at nag-iimbak ng object — ito ang may-ari. Ang @ObservedObject ay nagmamasid lamang sa isang object na ginawa sa ibang lugar at ipinasa sa pamamagitan ng initializer o property.
| Katangian | @StateObject | @ObservedObject |
|---|---|---|
| Pagmamay-ari | Gumagawa at nagmamay-ari ng object | Nagmamasid lamang |
| Pagsisimula | Sa loob ng View sa pamamagitan ng init/default | Mula sa labas, ipinasa sa pamamagitan ng parameter |
| Lifecycle | Nakatali sa lifecycle ng View | Hindi kontrolado ng View |
| Muling paggawa | Hindi muling ginagawa sa pag-update | Maaaring palitan mula sa labas |
| Bersyon ng iOS | iOS 14+ | iOS 13+ |
Ang patakaran ay simple: kung ang View ay gumagawa ng ObservableObject — gamitin ang @StateObject. Kung ang View ay tumatanggap lamang ng handa nang object mula sa parent — gamitin ang @ObservedObject. Ang paglabag sa patakarang ito ay humahantong sa alinman sa pagkawala ng data (kung gagamitin ang @ObservedObject para sa pagmamay-ari) o labis na paggawa ng object (kung gagamitin ang @StateObject para sa pagmamasid).
Ang @StateObject ay dapat gamitin sa mga View na pinagmumulan ng katotohanan para sa isang partikular na set ng data. Kasama sa karaniwang mga senaryo ang mga screen na may sariling view model, root screen ng navigation stack, at modal presentation na namamahala ng sariling estado.
struct ProfileView: View {
@StateObject var viewModel = ProfileViewModel()
var body: some View {
NavigationStack {
Form {
TextField("Name", text: $viewModel.name)
TextField("Email", text: $viewModel.email)
Button("I-save") {
viewModel.saveProfile()
}
}
.navigationTitle("Profile")
}
}
}
Ang pagsisimula ng @StateObject na may mga parameter ay nangangailangan ng espesyal na syntax, dahil independiyenteng pinamamahalaan ng SwiftUI ang paggawa ng object. Hindi mo basta-basta maipapasa ang mga parameter sa initializer — kailangan mong gumamit ng escaping closure o hiwalay na paraan ng paggawa.
Ayon sa Swift by Sundell (2024), ang pinakamalinis na paraan ay ang paggamit ng factory method o closure na tatawagin ng SwiftUI sa unang paggawa ng object. Isang alternatibong approach — simulan ang ObservableObject sa parent View at ipasa ito sa pamamagitan ng @StateObject gamit ang standard na initializer.
class UserViewModel: ObservableObject {
@Published var user: User
init(user: User) {
self.user = user
}
}
struct UserDetailView: View {
@StateObject var viewModel: UserViewModel
init(user: User) {
_viewModel = StateObject(wrappedValue: UserViewModel(user: user))
}
var body: some View {
Text(viewModel.user.name)
}
}
Mahalagang tandaan na ang initializer ng View na may @StateObject ay dapat gumamit ng underscore bago ang pangalan ng property (_viewModel) upang ma-access ang property wrapper mismo, hindi ang halaga nito. Ito ay isang standard na pattern ng Swift para sa pagtatrabaho sa mga property wrapper sa initializer.
Ang pinakakaraniwang pagkakamali ay ang paggamit ng @ObservedObject sa halip na @StateObject para sa View na dapat magmay-ari ng object. Sa kasong ito, sa bawat muling pagtatayo ng parent, ang object ay muling gagawin, na humahantong sa pagkawala ng lahat ng nakalap na data. Ang pagkakamaling ito ay lalong mapanlinlang sa mga kumplikadong hierarchy na may NavigationStack o TabView.
Upang maiwasan ang mga problemang ito, sundin ang simpleng patakaran: isang @StateObject bawat isang source of truth. Kung ang data ay dapat ibahagi sa maraming screen — gumawa ng @StateObject nang isang beses sa root View at ipasa ito sa pamamagitan ng @ObservedObject o @EnvironmentObject sa mga child element.
// ❌ Mali: @ObservedObject para sa pagmamay-ari ng object
struct BadView: View {
@ObservedObject var vm = ViewModel() // muling gagawin sa bawat update!
}
// ✅ Tama: @StateObject para sa pagmamay-ari
struct GoodView: View {
@StateObject var vm = ViewModel() // ginawa nang isang beses para sa buhay ng View
}
Mga Madalas Itanong
Ang @State ay gumagana sa value types (struct, string, numero) at iniimbak ang halaga nang direkta sa SwiftUI storage. Ang @StateObject ay gumagana sa reference types — mga klase na sumusunod sa ObservableObject. Ang @State ay angkop para sa simpleng lokal na estado, ang @StateObject ay para sa kumplikadong object na may logic at nai-publish na mga property.
Hindi, ang @StateObject ay available lamang mula sa iOS 14 pataas. Para sa iOS 13 gamitin ang @ObservedObject at gumawa ng ObservableObject sa parent View sa pamamagitan ng @State na may manu-manong pamamahala ng lifecycle. Alternatibo — gamitin ang @State na may struct sa halip na class para sa data na hindi nangangailangan ng reference semantics.
Ang child View ay gagawa ng sarili nitong kopya ng ObservableObject, ganap na independiyente mula sa parent. Ang mga pagbabago sa isa ay hindi makakaapekto sa isa pa. Ito ay halos palaging isang pagkakamali: gamitin ang @ObservedObject para sa pagtanggap ng object mula sa parent at @StateObject lamang para sa paggawa ng bagong object sa loob ng View.
Ang object ay nasisira kapag ang View na gumawa nito ay ganap na naalis mula sa SwiftUI hierarchy. Para sa isang screen sa NavigationStack, ito ay nangyayari sa pop mula sa navigation stack. Para sa modal window — sa pagsasara nito. Para sa TabView — sa pagpapalit ng tab, kung ang View ay hindi naka-cache.
Gumamit ng custom na init na may access sa property wrapper sa pamamagitan ng underscore: _viewModel = StateObject(wrappedValue: MyViewModel(param: value)). Ang pattern na ito ay nagpapahintulot sa pagpasa ng anumang mga parameter sa ObservableObject, habang pinapanatili ang garantiya ng isang beses na paggawa ng object sa buhay ng View.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din