@StateObject: ano ito, paggawa at pamamahala ng ObservableObject

May-akda: IT Sectr Nai-publish: 2026-06-26 Oras ng pagbabasa: 9 min

@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 — property wrapper para sa paggawa at pagmamay-ari ng ObservableObject sa loob ng View.
  • Isang beses na paggawa — ang object ay sinisimulan nang isang beses sa buhay ng View at hindi muling nililikha sa mga muling pagtatayo.
  • Source of truth — ang @StateObject ay pinagmumulan ng katotohanan sa hierarchy, hindi katulad ng @ObservedObject.
  • Lifecycle — ang object ay nabubuhay hangga't ang View ay nasa memorya at sinisira kasama nito.
  • Pagsisimula — ang @StateObject ay nangangailangan ng paunang halaga sa paggawa, karaniwan sa pamamagitan ng init na may mga parameter.

Ano ang @StateObject sa SwiftUI

@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.

swift
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)
        }
    }
}

Paano gumagana ang @StateObject

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.

Lifecycle ng @StateObject

  • Paggawa — sa unang paglitaw ng View sa screen, tinatawag ng SwiftUI ang initializer ng object at iniimbak ang reference.
  • Muling pagtatayo — sa pag-update ng parent View, hindi muling ginagawa ang object, ginagamit ang umiiral na instance.
  • Pagkasira — kapag umalis ang View sa screen at naalis mula sa hierarchy, tinatawag ng SwiftUI ang deinit ng object.

@StateObject vs @ObservedObject: mga pangunahing pagkakaiba

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-ariGumagawa at nagmamay-ari ng objectNagmamasid lamang
PagsisimulaSa loob ng View sa pamamagitan ng init/defaultMula sa labas, ipinasa sa pamamagitan ng parameter
LifecycleNakatali sa lifecycle ng ViewHindi kontrolado ng View
Muling paggawaHindi muling ginagawa sa pag-updateMaaaring palitan mula sa labas
Bersyon ng iOSiOS 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).

Kailan gagamitin ang @StateObject

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.

  • Screen na may view model — bawat screen na namamahala ng sarili nitong data at logic ay dapat gumawa ng view model nito sa pamamagitan ng @StateObject.
  • Root View — sa hierarchy ng NavigationStack o TabView, ang root element ay gumagawa ng data, at ang mga child ay tumatanggap ng mga ito sa pamamagitan ng @ObservedObject.
  • Modal window — ang .sheet at .fullScreenCover ay madalas na nangangailangan ng sariling @StateObject para sa pamamahala ng form o proseso.
  • Listahan na may pag-edit — bawat hilera ng listahan na naglalaman ng form sa pag-edit ay dapat may sariling @StateObject.
swift
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")
        }
    }
}

Pagsisimula ng @StateObject na may mga parameter

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.

swift
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.

Mga karaniwang pagkakamali sa @StateObject

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.

  • Pagkawala ng data sa navigation — kung ang isang child screen ay gumagamit ng @ObservedObject para sa sarili nitong view model, sa pagbabalik at muling pagbukas, ang data ay ma-reset.
  • Pagtagas ng memorya — ang paggawa ng @StateObject sa parent View na hindi kailanman inaalis ay maaaring humantong sa akumulasyon ng mga object, kung ang bawat child screen ay gumagawa din ng @StateObject nang walang kontrol.
  • Pagdoble ng object — ang pagpasa ng isang ObservableObject sa maraming @StateObject sa iba't ibang View ay lumilikha ng maraming independiyenteng instance na hindi nagsi-sync sa isa't isa.

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.

swift
// ❌ 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

Ano ang pagkakaiba ng @StateObject at @State?

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.

Maaari bang gamitin ang @StateObject sa iOS 13?

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.

Ano ang mangyayari kung gagamitin ko ang @StateObject sa isang child View kung saan ang object ay ipinasa mula sa parent?

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.

Kailan nasisira ang object na ginawa sa pamamagitan ng @StateObject?

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.

Paano magpasa ng mga parameter sa @StateObject sa pagsisimula?

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

  • @StateObject — property wrapper para sa paggawa at pagmamay-ari ng ObservableObject sa loob ng View, available mula sa iOS 14.
  • Garantiya ng isang beses na paggawa — ang object ay sinisimulan nang isang beses at hindi muling ginagawa sa muling pagtatayo ng View.
  • Source of truth — ang @StateObject ay pinagmumulan ng katotohanan, ang @ObservedObject ay tagamasid lamang.
  • Lifecycle — ang object ay nabubuhay hangga't ang View ay nasa SwiftUI hierarchy at nasisira kapag umalis ito.
  • Pagsisimula na may mga parameter — nangangailangan ng access sa property wrapper sa pamamagitan ng _viewModel at StateObject(wrappedValue:).
  • Pagkakamali sa pagmamay-ari — ang paggamit ng @ObservedObject para sa paggawa ng object ay humahantong sa pagkawala ng data sa muling pagtatayo.
  • Isang object — isang @StateObject — para sa shared data, gumawa ng @StateObject sa root View at ipasa sa child sa pamamagitan ng @ObservedObject.

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.

Pag-usapan ang proyekto

Basahin din