Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Specialized skill for iOS local data persistence solutions
.claude/skills/a5c-ai-ios-persistence-core-data-realm/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-10 | ✗→✓ | ▲ Improved | 164% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 123% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 130% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 138% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 181% | 0% |
This skill provides specialized capabilities for iOS local data persistence solutions including Core Data and Realm. It enables designing data models, implementing migrations, configuring iCloud sync, and optimizing database performance.
bash - Execute xcodebuild and swift commandsread - Analyze Core Data models and Realm schemaswrite - Generate model classes and configurationsedit - Update existing persistence codeglob - Search for model files and configurationsgrep - Search for patterns in persistence codeThis skill integrates with the following processes:
ios-core-data-implementation.js - Core Data setup and usageoffline-first-architecture.js - Offline data strategiesmobile-security-implementation.js - Secure data storageswift// Persistence/PersistenceController.swift import CoreData import CloudKit final class PersistenceController { static let shared = PersistenceController() let container: NSPersistentCloudKitContainer init(inMemory: Bool = false) { container = NSPersistentCloudKitContainer(name: "MyApp") if inMemory { container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null") } // Configure CloudKit guard let description = container.persistentStoreDescriptions.first else { fatalError("Failed to retrieve persistent store description") } description.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions( containerIdentifier: "iCloud.com.example.myapp" ) description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) container.loadPersistentStores { description, error in if let error = error { fatalError("Unable to load persistent stores: \(error)") } } container.viewContext.automaticallyMergesChangesFromParent = true container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy } // MARK: - Preview Support static var preview: PersistenceController = { let controller = PersistenceController(inMemory: true) // Add sample data return controller }() }
swift// Persistence/RealmManager.swift import RealmSwift final class RealmManager { static let shared = RealmManager() private init() { configureRealm() } private func configureRealm() { let config = Realm.Configuration( schemaVersion: 1, migrationBlock: { migration, oldSchemaVersion in if oldSchemaVersion < 1 { // Migration logic } } ) Realm.Configuration.defaultConfiguration = config } var realm: Realm { try! Realm() } }
swift// Models/Item+CoreDataClass.swift import Foundation import CoreData @objc(Item) public class Item: NSManagedObject { @nonobjc public class func fetchRequest() -> NSFetchRequest<Item> { return NSFetchRequest<Item>(entityName: "Item") } @NSManaged public var id: UUID @NSManaged public var title: String @NSManaged public var createdAt: Date @NSManaged public var isCompleted: Bool @NSManaged public var category: Category? } extension Item { static func create( in context: NSManagedObjectContext, title: String, category: Category? = nil ) -> Item { let item = Item(context: context) item.id = UUID() item.title = title item.createdAt = Date() item.isCompleted = false item.category = category return item } static func fetchAll(in context: NSManagedObjectContext) -> [Item] { let request = fetchRequest() request.sortDescriptors = [NSSortDescriptor(keyPath: \Item.createdAt, ascending: false)] return (try? context.fetch(request)) ?? [] } static func fetchIncomplete(in context: NSManagedObjectContext) -> [Item] { let request = fetchRequest() request.predicate = NSPredicate(format: "isCompleted == NO") request.sortDescriptors = [NSSortDescriptor(keyPath: \Item.createdAt, ascending: false)] return (try? context.fetch(request)) ?? [] } }
swift// Data/Repository/ItemRepository.swift import Foundation import CoreData import Combine protocol ItemRepositoryProtocol { func fetchItems() -> AnyPublisher<[Item], Error> func addItem(title: String) -> AnyPublisher<Item, Error> func updateItem(_ item: Item) -> AnyPublisher<Void, Error> func deleteItem(_ item: Item) -> AnyPublisher<Void, Error> } final class ItemRepository: ItemRepositoryProtocol { private let container: NSPersistentContainer private let backgroundContext: NSManagedObjectContext init(container: NSPersistentContainer = PersistenceController.shared.container) { self.container = container self.backgroundContext = container.newBackgroundContext() self.backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy } func fetchItems() -> AnyPublisher<[Item], Error> { Future { [weak self] promise in guard let self = self else { return } self.backgroundContext.perform { do { let items = try Item.fetchAll(in: self.backgroundContext) promise(.success(items)) } catch { promise(.failure(error)) } } } .eraseToAnyPublisher() } func addItem(title: String) -> AnyPublisher<Item, Error> { Future { [weak self] promise in guard let self = self else { return } self.backgroundContext.perform { let item = Item.create(in: self.backgroundContext, title: title) do { try self.backgroundContext.save() promise(.success(item)) } catch { self.backgroundContext.rollback() promise(.failure(error)) } } } .eraseToAnyPublisher() } func updateItem(_ item: Item) -> AnyPublisher<Void, Error> { Future { [weak self] promise in guard let self = self else { return } self.backgroundContext.perform { do { try self.backgroundContext.save() promise(.success(())) } catch { self.backgroundContext.rollback() promise(.failure(error)) } } } .eraseToAnyPublisher() } func deleteItem(_ item: Item) -> AnyPublisher<Void, Error> { Future { [weak self] promise in guard let self = self else { return } self.backgroundContext.perform { self.backgroundContext.delete(item) do { try self.backgroundContext.save() promise(.success(())) } catch { self.backgroundContext.rollback() promise(.failure(error)) } } } .eraseToAnyPublisher() } }
swift// Models/TaskObject.swift import RealmSwift class TaskObject: Object, Identifiable { @Persisted(primaryKey: true) var id: ObjectId @Persisted var title: String = "" @Persisted var dueDate: Date? @Persisted var isCompleted: Bool = false @Persisted var priority: Int = 0 @Persisted var tags: List<TagObject> @Persisted(originProperty: "tasks") var project: LinkingObjects<ProjectObject> convenience init(title: String, dueDate: Date? = nil, priority: Int = 0) { self.init() self.title = title self.dueDate = dueDate self.priority = priority } } class TagObject: Object, Identifiable { @Persisted(primaryKey: true) var id: ObjectId @Persisted(indexed: true) var name: String = "" @Persisted var color: String = "#000000" } class ProjectObject: Object, Identifiable { @Persisted(primaryKey: true) var id: ObjectId @Persisted var name: String = "" @Persisted var tasks: List<TaskObject> }
swift// Data/Repository/TaskRealmRepository.swift import Foundation import RealmSwift import Combine protocol TaskRepositoryProtocol { func fetchTasks() -> AnyPublisher<[TaskObject], Error> func addTask(_ task: TaskObject) -> AnyPublisher<Void, Error> func updateTask(_ task: TaskObject, with updates: (TaskObject) -> Void) -> AnyPublisher<Void, Error> func deleteTask(_ task: TaskObject) -> AnyPublisher<Void, Error> } final class TaskRealmRepository: TaskRepositoryProtocol { private let realm: Realm init(realm: Realm = RealmManager.shared.realm) { self.realm = realm } func fetchTasks() -> AnyPublisher<[TaskObject], Error> { Just(Array(realm.objects(TaskObject.self).sorted(byKeyPath: "dueDate"))) .setFailureType(to: Error.self) .eraseToAnyPublisher() } func addTask(_ task: TaskObject) -> AnyPublisher<Void, Error> { Future { [weak self] promise in guard let self = self else { return } do { try self.realm.write { self.realm.add(task) } promise(.success(())) } catch { promise(.failure(error)) } } .eraseToAnyPublisher() } func updateTask(_ task: TaskObject, with updates: (TaskObject) -> Void) -> AnyPublisher<Void, Error> { Future { [weak self] promise in guard let self = self else { return } do { try self.realm.write { updates(task) } promise(.success(())) } catch { promise(.failure(error)) } } .eraseToAnyPublisher() } func deleteTask(_ task: TaskObject) -> AnyPublisher<Void, Error> { Future { [weak self] promise in guard let self = self else { return } do { try self.realm.write { self.realm.delete(task) } promise(.success(())) } catch { promise(.failure(error)) } } .eraseToAnyPublisher() } }
swift-swiftui - iOS app developmentmobile-security - Secure data storageoffline-storage - Cross-platform offline patterns| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 25,518 | 23,583 | -8% | 1 | 1 | 0% | 4,339 | 7,128 | +64% | 0 | 0 | — |
case-02 | fail→fail | 32,237 | 28,627 | -11% | 1 | 1 | 0% | 6,100 | 7,395 | +21% | 0 | 0 | — |
case-03 | fail→fail | 17,429 | 26,461 | +52% | 1 | 1 | 0% | 3,497 | 7,998 | +129% | 0 | 0 | — |
case-04 | pass→pass | 12,243 | 11,645 | -5% | 1 | 1 | 0% | 2,362 | 5,626 | +138% | 0 | 0 | — |
case-05 | pass→pass | 14,187 | 13,663 | -4% | 1 | 1 | 0% | 1,673 | 4,709 | +181% | 0 | 0 | — |
case-06 | pass→pass | 11,365 | 4,757 | -58% | 1 | 1 | 0% | 1,184 | 4,148 | +250% | 0 | 0 | — |
case-07 | pass→pass | 10,197 | 14,944 | +47% | 1 | 1 | 0% | 1,893 | 5,097 | +169% | 0 | 0 | — |
case-08 | pass→pass | 18,195 | 17,085 | -6% | 1 | 1 | 0% | 2,802 | 6,830 | +144% | 0 | 0 | — |
case-09 | pass→pass | 6,307 | 7,899 | +25% | 1 | 1 | 0% | 1,285 | 4,634 | +261% | 0 | 0 | — |
case-10 | fail→pass | 14,179 | 12,358 | -13% | 1 | 1 | 0% | 1,835 | 4,850 | +164% | 0 | 0 | — |
case-11 | pass→pass | 17,372 | 12,116 | -30% | 1 | 1 | 0% | 2,258 | 4,564 | +102% | 0 | 0 | — |
case-12 | pass→pass | 14,475 | 15,918 | +10% | 1 | 1 | 0% | 2,564 | 5,345 | +108% | 0 | 0 | — |
case-13 | fail→pass | 19,255 | 14,559 | -24% | 1 | 1 | 0% | 2,729 | 6,099 | +123% | 0 | 0 | — |
case-14 | pass→pass | 11,194 | 9,182 | -18% | 1 | 1 | 0% | 2,168 | 5,021 | +132% | 0 | 0 | — |
case-15 | pass→pass | 16,685 | 12,409 | -26% | 1 | 1 | 0% | 2,136 | 4,574 | +114% | 0 | 0 | — |
case-16 | fail→pass | 14,130 | 5,028 | -64% | 1 | 1 | 0% | 1,788 | 4,117 | +130% | 0 | 0 | — |
case-17 | pass→pass | 18,745 | 20,295 | +8% | 1 | 1 | 0% | 2,667 | 5,983 | +124% | 0 | 0 | — |
case-18 | pass→pass | 22,865 | 26,582 | +16% | 1 | 1 | 0% | 3,298 | 7,501 | +127% | 0 | 0 | — |
case-19 | fail→fail | 20,597 | 19,948 | -3% | 1 | 1 | 0% | 2,907 | 6,016 | +107% | 0 | 0 | — |
case-20 | pass→pass | 8,817 | 10,350 | +17% | 1 | 1 | 0% | 1,778 | 5,434 | +206% | 0 | 0 | — |
case-21 | pass→pass | 15,784 | 13,151 | -17% | 1 | 1 | 0% | 3,246 | 6,039 | +86% | 0 | 0 | — |
case-22 | fail→fail | 21,777 | 44,112 | +103% | 1 | 1 | 0% | 3,380 | 11,385 | +237% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +14 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.