From 7eb7cb81d40b56301849cbf61018ab52bac19b58 Mon Sep 17 00:00:00 2001 From: alexandrev-tibco Date: Tue, 21 Jul 2026 15:22:42 +0200 Subject: [PATCH] Fix sync iCloud del Goal: accessor nil-tolerante en createdAt (Goal/Account/InvestmentSource) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El modelo declara createdAt optional=YES pero las clases lo tenían @NSManaged var createdAt: Date (no-opcional). Al materializar un registro importado por CloudKit con createdAt transitoriamente nil, el acceso revienta el merge → contribuye al CKErrorPartialFailure y a que el Goal no sincronice. Mismo patrón safeValue/setManagedValue ya aplicado a Snapshot (hotfix b76b8f8) que no cubrió estas 3. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01LZFmGhbWzibhApev3C4554 --- .../Models/CoreData/Account+CoreDataClass.swift | 8 +++++++- PortfolioJournal/Models/CoreData/Goal+CoreDataClass.swift | 8 +++++++- .../Models/CoreData/InvestmentSource+CoreDataClass.swift | 8 +++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/PortfolioJournal/Models/CoreData/Account+CoreDataClass.swift b/PortfolioJournal/Models/CoreData/Account+CoreDataClass.swift index 4d30d43..200c95f 100644 --- a/PortfolioJournal/Models/CoreData/Account+CoreDataClass.swift +++ b/PortfolioJournal/Models/CoreData/Account+CoreDataClass.swift @@ -15,7 +15,13 @@ public class Account: NSManagedObject, Identifiable { get { safeValue(forKey: "name", fallback: "") } set { setManagedValue(newValue, forKey: "name") } } - @NSManaged public var createdAt: Date + // createdAt is optional in the model; a non-optional @NSManaged Date crashes the + // CloudKit merge when an imported record materialises with a transient nil. + // Same nil-tolerant accessor pattern already applied to Snapshot. + @objc public var createdAt: Date { + get { safeValue(forKey: "createdAt", fallback: .distantPast) } + set { setManagedValue(newValue, forKey: "createdAt") } + } @NSManaged public var currency: String? @NSManaged public var inputMode: String @NSManaged public var notificationFrequency: String diff --git a/PortfolioJournal/Models/CoreData/Goal+CoreDataClass.swift b/PortfolioJournal/Models/CoreData/Goal+CoreDataClass.swift index e8adad3..9a0dcc7 100644 --- a/PortfolioJournal/Models/CoreData/Goal+CoreDataClass.swift +++ b/PortfolioJournal/Models/CoreData/Goal+CoreDataClass.swift @@ -18,7 +18,13 @@ public class Goal: NSManagedObject, Identifiable { @NSManaged public var targetAmount: NSDecimalNumber? @NSManaged public var targetDate: Date? @NSManaged public var isActive: Bool - @NSManaged public var createdAt: Date + // createdAt is optional in the model; a non-optional @NSManaged Date crashes the + // CloudKit merge when an imported record materialises with a transient nil. + // Same nil-tolerant accessor pattern already applied to Snapshot. + @objc public var createdAt: Date { + get { safeValue(forKey: "createdAt", fallback: .distantPast) } + set { setManagedValue(newValue, forKey: "createdAt") } + } @NSManaged public var account: Account? public override func awakeFromInsert() { diff --git a/PortfolioJournal/Models/CoreData/InvestmentSource+CoreDataClass.swift b/PortfolioJournal/Models/CoreData/InvestmentSource+CoreDataClass.swift index c36f2e4..cfab644 100644 --- a/PortfolioJournal/Models/CoreData/InvestmentSource+CoreDataClass.swift +++ b/PortfolioJournal/Models/CoreData/InvestmentSource+CoreDataClass.swift @@ -19,7 +19,13 @@ public class InvestmentSource: NSManagedObject, Identifiable { @NSManaged public var customFrequencyMonths: Int16 @NSManaged public var isActive: Bool @NSManaged public var monthlyContribution: NSDecimalNumber? - @NSManaged public var createdAt: Date + // createdAt is optional in the model; a non-optional @NSManaged Date crashes the + // CloudKit merge when an imported record materialises with a transient nil. + // Same nil-tolerant accessor pattern already applied to Snapshot. + @objc public var createdAt: Date { + get { safeValue(forKey: "createdAt", fallback: .distantPast) } + set { setManagedValue(newValue, forKey: "createdAt") } + } @NSManaged public var category: Category? @NSManaged public var account: Account? @NSManaged public var snapshots: NSSet?