Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Realm append data to a type List<t>

Tags:

ios

swift

realm

I'm trying to go through data and save it in my model, however whatever i do i keep getting the following error: Can't mutate a persisted array outside of a write transaction.. What am i doing wrong? i'm appending each match to the league however it does not seem to work?

realm model

class League: Object {
    dynamic var id: Int = 0
    dynamic var name: String? = ""
    var matches = List<Match>()

    override class func primaryKey() -> String {
        return "id"
    }
}

class Match: Object {
    dynamic var matchId: Int = 0
    dynamic var date: NSDate?
    dynamic var homeName: String? = ""
    dynamic var awayName: String? = ""
    dynamic var awayScore: Int = 0
    dynamic var homeScore: Int = 0
    dynamic var leagueName: String? = ""
    dynamic var homeLogo: NSData?
    dynamic var awayLogo: NSData?
}

Code

    for (_, item) in result {
        if let leagueId = item["league"].int,
            let leagueName = item["name"].string,
            let allMatches = item["matches"].array {
                let league = League()
                league.name = leagueName
                league.id = leagueId

                for match in allMatches {
                    if let matchId = match["matchId"].int,
                        let tournament = match["tournament"].string,
                        let homeTeam = match["homeName"].string,
                        let awayTeam = match["awayName"].string,
                        let homeScore = match["homeScore"].int,
                        let awayScore = match["awayScore"].int,
                        let homeLogo = match["homeLogo"].string,
                        let awayLogo = match["awayLogo"].string,
                        let date = match["date"].string {
                            if let awayLogoUrl = NSURL(string: awayLogo),
                                let homeLogoUrl = NSURL(string: homeLogo) {
                                    if let awayLogoData = NSData(contentsOfURL: awayLogoUrl),
                                        let homeLogoData = NSData(contentsOfURL: homeLogoUrl) {
                                            let matchObject = Match()
                                            matchObject.matchId = matchId
                                            matchObject.leagueName = tournament
                                            matchObject.homeName = homeTeam
                                            matchObject.awayName = awayTeam
                                            matchObject.homeScore = homeScore
                                            matchObject.awayScore = awayScore
                                            matchObject.homeLogo = homeLogoData
                                            matchObject.awayLogo = awayLogoData

                                            let formatter = NSDateFormatter()
                                            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
                                            formatter.timeZone = NSTimeZone(abbreviation: "CET")
                                            matchObject.date = formatter.dateFromString(date)!

                                            league.matches.append(matchObject)
                                    }
                            }
                    }

                    print(league)

                    try! realm.write {
                        realm.add(league, update: true)
                    }
                }
        }
    }
}
like image 641
Peter Pik Avatar asked Mar 09 '26 15:03

Peter Pik


1 Answers

Simplifying your code to show only the general structure helps to reveal the issue:

let league = League()
league.name = leagueName
league.id = leagueId

for match in allMatches {
    if … {
        let matchObject = Match()
        …

        league.matches.append(matchObject)
    }

    print(league)

    try! realm.write {
        realm.add(league, update: true)
    }
}

This is the sequence of events: You start by creating a standalone, unpersisted League instance, league. For each match, you create a standalone, unpersisted Match instance and append it to league.matches. You then create a write transaction, and save league to the Realm. From this point, league is no longer standalone, and may only be modified within a write transaction. On the next iteration of the loop you create another Match instance and attempt to append it to league.matches. This throws since league is persisted and we're not in a write transaction.

One solution here would be to restructure the code so you only save league to the Realm once, like so:

let league = League()
league.name = leagueName
league.id = leagueId

for match in allMatches {
    if … {
        let matchObject = Match()
        …

        league.matches.append(matchObject)
    }
}

print(league)

try! realm.write {
    realm.add(league, update: true)
}
like image 169
bdash Avatar answered Mar 12 '26 08:03

bdash