Search code examples
data-bindingswiftuiobservedobject

Can not Reach to Array Element from Another View SwiftUI


GitHub Project Link

I have a creditCard Model and CreditCards class that has a function to append creditCard.

class CreditCard: ObservableObject, Identifiable {
@Published var _id: String = UUID().uuidString
@Published var _cardOwnerName : String = ""
@Published var _cardNumber: String = ""
@Published var _cardExpMonth: String = ""
@Published var _cardExpYear: String = ""
@Published var _cardName: String = ""
@Published var _ccv: String = ""

@Published var items = [CreditCard]()

init(cardOwnerName: String, cardNumber: String, cardExpMonth: String,cardExpYear: String, cardName:String, ccv:String)
    {
        self._cardOwnerName = cardOwnerName
        self._cardNumber = cardNumber
        self._cardExpMonth = cardExpMonth
        self._cardExpYear = cardExpYear
        self._cardName = cardName
        self._ccv = ccv
    }
 }

class CreditCards: ObservableObject {
@Published var items = [CreditCard]()


func appendNewCreditCard(creditCard: CreditCard) {
    objectWillChange.send()
    items.append(CreditCard(cardOwnerName: creditCard._cardOwnerName, cardNumber: creditCard._cardNumber, cardExpMonth: creditCard._cardExpMonth, cardExpYear: creditCard._cardExpYear, cardName: creditCard._cardName, ccv: creditCard._ccv))
   }
}

I am appending a new credit card when all the conditions are met through a button.

struct CardInfo : View {
@State var creditCard : CreditCard
@ObservedObject var creditCards = CreditCards()

  CreditCardTextField(data: $cardNumberText, tFtext: "Kredi Kart Numarasi", tFImage: "credit")
                .textContentType(.oneTimeCode)
                .keyboardType(.numberPad)
                .onReceive(Just(cardNumberText)) { cardNumberdata in
                    if cardNumberdata.count == 16 {
                        self.creditCard._cardNumber = self.cardNumberText
                    }
            }

  Button(action: {
                    self.isSaved.toggle()
                    if self.creditCard._cardNumber == "" {
                        self.showingAlert = true
                    } else if self.creditCard._cardNumber.count == 16 {
                        self.successAlert = true
                        self.creditCards.objectWillChange.send()
                        self.creditCards.appendNewCreditCard(creditCard: creditCard)
                        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                           self.successAlert = false    // hide popup
                           self.showAddressView = true    // eg. activate navigation link
                        }
                    }
                }

When I try to show text in my PaymentMethodView as below I cannot see any text on PaymentMethodView.

struct PaymentMethodView: View {
@ObservedObject var creditCards = CreditCardArray()
var body: some View {
    VStack {
        TopBarPM()
        MiddleView()
            .padding()
        DetailLine()
        VStack {
            HStack {
                Image("credit")
                VStack {
                    ForEach(creditCards.items) { item in
                        Text(item._cardName)
                }
            }
        }
        Spacer()
    }
}

}

Now I need to show those credit cards in another in PaymentMethodView


Solution

  • Thank you for sharing. It seems that the AddCreditCardView and PaymentMethodView (where you're referencing a CreditCardArray) are two completely separated views which aren't calling each other. Therefore I would suggest to use the CreditCardArray as EnvironmentObject.

    Currently you're creating in both views new ObservedObject CreditCardArrays, therefore you don't have any data to show in the PaymentMethodView.

    When using an EnvironmentObject you can inject it into a view which holds AddCreditCardView and PaymentMethodView. Just choose the SceneDelegate for it and replace the line:

    let contentView = ContentView()
    

    with

    let contentView = ContentView().environmentObject(CreditCardArray())
    

    Here you're creating an object of CreditCardArray which you can access throughout the whole application.

    You can access this object now by replacing the following line (in AddCreditCardView and PaymentMethodView):

    @ObservedObject var creditCards = CreditCardArray()
    

    with

    @EnvironmentObject var creditCards: CreditCardArray
    

    in order to access the previously created array instead of creating a new one.