RestKit, CoreData and Swift - I can't seem to fetch results back out
The answer is that apparently Swift does not like casting the fetch result as an optional. I have to put the result into a local variable and then set the optional:
var currentUser: User? {
if !_currentUser {
var error: NSError? = nil
let request = NSFetchRequest(entityName: "User")
let recordCount = self.managedObjectContext.countForFetchRequest(request, error:&error)
NSLog("user records found: \(recordCount)")
var result = self.managedObjectContext.executeFetchRequest(request, error:&error)
for resultItem : AnyObject in result {
var currentUserItem = resultItem as User
NSLog("Fetched User for \(currentUserItem.firstname) \(currentUserItem.lastname)")
_currentUser = currentUserItem
}
}
return _currentUser;
}
Here is my setup and teardown of RestKit in Swift in case anyone (like niiamon) finds it helpful:
From my RestApi.swift:
var objectStore: RKManagedObjectStore = RKManagedObjectStore()
init() {
configureRestKit()
}
func configureRestKit() {
let objectManager = RKObjectManager(baseURL: NSURL.URLWithString(baseUrl))
//objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
RKObjectManager.setSharedManager(objectManager)
objectStore = RKManagedObjectStore(managedObjectModel: managedObjectModel())
let dataPath = "\(RKApplicationDataDirectory())/MyApp.sqlite"
NSLog("Setting up store at \(dataPath)")
objectStore.addSQLitePersistentStoreAtPath(dataPath, fromSeedDatabaseAtPath: nil, withConfiguration: nil, options: optionsForSqliteStore(), error: nil)
objectStore.createManagedObjectContexts()
objectStore.managedObjectCache = RKInMemoryManagedObjectCache(managedObjectContext: objectStore.persistentStoreManagedObjectContext)
objectManager.managedObjectStore = objectStore
// -- Declare routes -- //
// Login Route
objectManager.addResponseDescriptor(userLoginResponseDescriptor())
objectManager.addResponseDescriptor(eventLoginResponseDescriptor())
objectManager.router.routeSet.addRoute(RKRoute(name:kUserLoginRouteName, pathPattern: "/login", method: RKRequestMethod.POST))
}
func tearDownRestKit() {
// Cancel any network operations and clear the cache
RKObjectManager.sharedManager().operationQueue.cancelAllOperations()
NSURLCache.sharedURLCache().removeAllCachedResponses()
// Cancel any object mapping in the response mapping queue
RKObjectRequestOperation.responseMappingQueue().cancelAllOperations()
// Ensure the existing defaultStore is shut down
NSNotificationCenter.defaultCenter().removeObserver(RKManagedObjectStore.defaultStore())
RKObjectManager.setSharedManager(nil)
RKManagedObjectStore.setDefaultStore(nil)
}
func userMapping() -> RKEntityMapping {
let userMapping = RKEntityMapping(forEntityForName: "User", inManagedObjectStore: objectStore)
var userDictionary = ["id": "id", "created_at": "createdAt", "updated_at": "updatedAt", "username": "username", "email": "email", "firstname": "firstname", "lastname": "lastname", "organization": "organization"]
userMapping.addAttributeMappingsFromDictionary(userDictionary)
let tokenMapping = RKEntityMapping(forEntityForName: "ApiToken", inManagedObjectStore: objectStore)
tokenMapping.addAttributeMappingsFromArray(["token", "expiration"])
userMapping.addRelationshipMappingWithSourceKeyPath("tokens", mapping:tokenMapping)
return userMapping
}
func userLoginResponseDescriptor() -> RKResponseDescriptor {
let userResponseDescriptor = RKResponseDescriptor(mapping: userMapping(), method: RKRequestMethod.POST, pathPattern: "/login", keyPath: "user", statusCodes: NSIndexSet(index: 200))
return userResponseDescriptor
}
func managedObjectModel() -> NSManagedObjectModel {
return NSManagedObjectModel.mergedModelFromBundles(nil)
}
func optionsForSqliteStore() -> NSDictionary {
return [
NSInferMappingModelAutomaticallyOption: true,
NSMigratePersistentStoresAutomaticallyOption: true
];
}
Return Results from CoreData directly into Class
The compiler complains because you did not specify a return type for your function,
it should be
class func getAllLocations() -> [Locations] { ... }
There are also some unnecessary type annotations, and all the objects can be
declared as constants:
class func getAllLocations() -> [Locations] {
let appDel = (UIApplication.sharedApplication().delegate as AppDelegate)
let context = appDel.managedObjectContext!
let request = NSFetchRequest(entityName: "Locations")
request.returnsObjectsAsFaults = false
let results = context.executeFetchRequest(request, error: nil)!
return results as [Locations]
}
Note also that
let results = context.executeFetchRequest(request, error: nil)!
will throw a runtime exception if the executing the fetch request failed.
You should use an optional binding and some error handling or fallback,
for example
if let results = context.executeFetchRequest(request, error: nil) as? [Locations] {
return results
} else {
// Failed, return empty list. (Alternatively, report error.)
return []
}
Fetching From CoreData returns AnyObject
context.executeFetchRequest()
returns [AnyObject]
, not AnyObject
.
You need to do:
if let results = context.executeFetchRequest(fetchRequest2) as? [MyObjectType] {
for object in results {
//do thing
}
}
Issue with Core Data fetch request
I got the viewContext from the container because I needed the UI thread. I guess that was my problem. I solved it passing the context I used to fetch and create the data and dispatching the request to the main queue:
func loadData(with context: NSManagedObjectContext) {
context.perform {
DispatchQueue.main.async {
let request: NSFetchRequest<EntityName> = EntityName.fetchRequest()
let data = try? context.fetch(request)
self.data = data!
self.setUI()
}
}
}
I hope it helps.
How to Fetch Coredata?
You are very close, type of users
is [User]
so an array of User
objects, so you can get to token of each User
with:
let managedContext = coreDataStack.managedContext
let request = NSFetchRequest<User>(entityName: "User")
do {
let users = try managedContext.fetch(request)
for user in users {
print(user.token)
}
} catch {
print(error.localizedDescription)
}
or if you want to get last (.last
) or first (.first
) User
you can just do:
do {
let users = try managedContext.fetch(request)
if let user = users.first {
print(user.token)
}
} catch {
print(error.localizedDescription)
}
Fetch Local Data from CoreData using RestKit 0.2
Using addInMemoryPersistentStore:
does not save to disk so when the app closes all data is gone. Look at using addSQLitePersistentStoreAtPath:
instead.
Sync coredata with restkit
RestKit will work with your existing core data model. You aren't forced to use the active record additions at all - feel free to ignore it.
As to your question. Before you try and fix everything by using RestKit. I recommend understanding exactly what you are trying to achieve with this "sync process". In fact RestKit does not magically sync anything (although there was that branch somewhere...). If you do not understand synchronization first, you will not be able to develop this system well.
IOS CoreData fetch duplicates on each view load
It because you create new data in your loop with this code
let order = FailedOrderEntity(context: context)
to fetch data with entity class model use this code
var fetched: [FailedOrderEntity] = []
let fetchRequest: NSFetchRequest<FailedOrderEntity> = FailedOrderEntity.fetchRequest()
do{
try fetched = context.fetch(fetchRequest)
} catch {}
How to retrieve CoreData that satisfies a condition swift 2
You need to add a NSPredicate to your fetchRequest.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/
fetchRequest.predicate = NSPredicate(format: "flag == %@", "3")
Related Topics
Swift: Protocol VS. Struct VS. Class
Change Title of a Navigation Bar Button Item
Calculate Distance Between My Location and a Mapkit Pin on Swift
How to Read Heart Rate from iOS Healthkit App Using Swift
How to Run My Performance Tests More Than Ten Times
Swift Add Line Above to Control
Set the Center of a Uibutton Programmatically - Swift
How to Call Presentviewcontroller in Uiview Class
Get Progress of Uinavigationcontroller Swipe Back
API to Capture Live Photos in iOS9
How to Change the Font Size of a Uilabel in Swift
Cannot Convert Value of Type 'String.Type' to Expected Argument Type 'String!'
How to Handle Oauth-Style Log Ins with Imessage Apps in iOS 10, Xcode 8
Memory Usage Keeps Rising on Older Devices Using Metal