我已经在一个新的基于Swift的应用程序(目前是XCode 6 beta 3)中成功设置了RestKit到CoreData的映射实现。我知道导入映射正在使用我的RestKit JSON调用,因为我可以检查sqlite数据库并查看我的数据。但是,我无法在NSFetchRequest中将数据从数据存储中取出。我做错了什么?
我将保留所有RestKit设置和拆卸,因为它非常标准并且看起来效果很好。所以这是我的AppDelegate查询代码似乎无法正常工作:
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 {
_currentUser = resultItem as? User
if _currentUser {
NSLog("Fetched User for \(_currentUser!.firstname) \(_currentUser!.lastname)")
}
}
}
return _currentUser;
}
self.managedObjectContext从我的AppDelegate引用它来从RestKit shareObject获取上下文:
var managedObjectContext: NSManagedObjectContext {
return RKObjectManager.sharedManager().managedObjectStore.mainQueueManagedObjectContext
}
看起来提取请求成功,因为for / in循环中出现断点。但是,当我检查resultItem或_currentUser对象时,它们显示为空,并且" if _currentUser" NSLog永远不会发射。
有什么想法吗?我是否对在Swift中恢复数据做出了错误的假设?
编辑2:
问题源于我尝试将resultItem置于Optional中。如果声明_currentUser没有可选项并删除as?可选的强制转换查询返回一个正确的用户对象:
for resultItem : AnyObject in result {
_currentUser = resultItem as User
NSLog("Fetched User for \(_currentUser.firstname) \(_currentUser.lastname)")
}
编辑: 我在主要获取请求之前添加了一个记录计数,它正确地显示了1条记录。因此,我尝试将获取结果映射到用户对象的方式出了问题。这是我的用户类:
import Foundation
import CoreData
class User: NSManagedObject {
@NSManaged
var id: Int32
@NSManaged
var createdAt: NSDate
@NSManaged
var udpatedAt: NSDate
@NSManaged
var username: String
@NSManaged
var email: String
@NSManaged
var firstname: String
@NSManaged
var lastname: String
@NSManaged
var organization: String
@NSManaged
var tokens: NSArray
}
答案 0 :(得分:6)
答案是显然Swift不喜欢将获取结果作为可选项进行转换。我必须将结果放入局部变量,然后设置可选:
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;
}
以下是我在Swift中设置和拆解RestKit的情况,以防任何人(如niiamon)发现它有用:
来自我的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
];
}