I've managed to create my UICollectionViewController with swift, and implement the NSFetchedResultsController and fetch stuff from my CoreData model. All good there... But...
I can't seem to call any of the NSFetchedResultsControllerDelegate methods from within my extension. Code is as follows:
extension MainsViewController: NSFetchedResultsControllerDelegate {
func fetchedResultsController() -> NSFetchedResultsController {
// if(fetchedResultsController != nil){
// return fetchedResultsController()
// }
var fetchRequest = NSFetchRequest()
var context: NSManagedObjectContext = RKObjectManager.sharedManager().managedObjectStore.mainQueueManagedObjectContext
var entity = NSEntityDescription.entityForName("Dessert", inManagedObjectContext: context)
fetchRequest.entity = entity
fetchRequest.fetchBatchSize = 20
var sortDescriptor = NSSortDescriptor(key: "createdAt", ascending: false)
let sortDescriptors = [sortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
fetchedResultsController().delegate = self
var aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: "Master")
var error: NSError?
if !aFetchedResultsController.performFetch(&error){
println("An error:\(error) occured.")
}
return aFetchedResultsController
}
//Here is where i would call *#optional func controllerWillChangeContent(_ controller: NSFetchedResultsController!)* etc. etc.
}
But swift doesnt recognise theese methods. I can't figure out what it is I am missing.
Would be great if someone could help me out.
Thanks in advance
Chris
I think it should something like this:
var fetchedResultsController: NSFetchedResultsController {
get {
var fetchRequest = NSFetchRequest()
var context: NSManagedObjectContext = RKObjectManager.sharedManager().managedObjectStore.mainQueueManagedObjectContext
var entity = NSEntityDescription.entityForName("Dessert", inManagedObjectContext: context)
fetchRequest.entity = entity
fetchRequest.fetchBatchSize = 20
var sortDescriptor = NSSortDescriptor(key: "createdAt", ascending: false)
let sortDescriptors = [sortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
self.fetchedResultsController.delegate = self
var aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: "Master")
var error: NSError?
if !aFetchedResultsController.performFetch(&error){
println("An error:\(error) occured.")
}
return aFetchedResultsController
}
}
So your MainsViewController is a class, as I said in the comment above, so the first line has to look like this:
class MainsViewController: UIViewController, NSFetchedResultsControllerDelegate {
Unfortunatly I cannot test the code, but this can be understood like this: You have a property called fetchedResultsController and this will execute, when the fetchedResultsController is getting. So in the getter like you would do it in objective-c with a lazy getting method.
I found out that it was simply the auto complete feature that wasn't suggesting the method to me. Typing it out manually 'fixed' the issue. Sorry for wasting everybody's time...
Chris
Related
This is my first Swift project also with CoreData. Swift doesn't have return instancetype like in Objective C.
In Swift - CoreData class, I am using common base class for NSManagedObject. There I have implemented a class function.
class func FRCWith(sortArray: [NSSortDescriptor], predicate: NSPredicate? = nil, mainContext: NSManagedObjectContext = CoreDataManager.shared.managedObjectContext) -> NSFetchedResultsController<NSManagedObject> {
let className = self.nameOfTheClass
let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest.init(entityName: className)
fetchRequest.sortDescriptors = sortArray
fetchRequest.fetchBatchSize = 4
if let predicateValue = predicate {
fetchRequest.predicate = predicateValue
}
let fetchedResultsController: NSFetchedResultsController<NSManagedObject> = NSFetchedResultsController.init(fetchRequest: fetchRequest, managedObjectContext: mainContext, sectionNameKeyPath: nil, cacheName: nil)
do {
try fetchedResultsController.performFetch()
} catch {
print(error.localizedDescription)
}
return fetchedResultsController
}
I want to return NSFetchedResultsController<customCoreDataClass> instead of common NSFetchedResultsController<NSManagedObject>.
var schoolvalue: NSFetchedResultsController<SchoolDetails> = SchoolDetails.FRCWith([sort])
var schoolvalue: NSFetchedResultsController<StudentDetails> = StudentDetails.FRCWith([sort], preidcate)
Right now I am using in for loop like this and checking is that FRC as! customClass
let loopValue: SchoolDetails = someFRC.object(at: IndexPath.init(row: value, section: 0)) as! SchoolDetails
Found some kind of solution in StackOverflow. That T thing, I do not understand that.
Is that possible make a method like that?
Thanks, #Paulw11 for an answer.
Randomly app crash when init
let fetchedResultsController: NSFetchedResultsController<T> = NSFetchedResultsController<T>(fetchRequest: fetchRequest, managedObjectContext: mainContext, sectionNameKeyPath: nil, cacheName: nil)
from below answer.
Because
let fetchRequest:NSFetchRequest<T> = T.fetchRequest() as! NSFetchRequest<T>\\ line return nil. There is no crash below iOS 10.x.
It only occurs when downloading from App store or Testflight.
You can use Swift generics for this. You specify a placeholder, often T is used but it doesn't have to be, that "stands in" for the actual class that will be used. In this case you need to specify that T must be a NSManagedObject or a subclass of NSManagedObect
Declare your function as:
class func FRCWith<T: NSManagedObject>(sortArray: [NSSortDescriptor], predicate: NSPredicate? = nil, mainContext: NSManagedObjectContext) throws -> NSFetchedResultsController<T> {
let fetchRequest:NSFetchRequest<T> = T.fetchRequest() as! NSFetchRequest<T>
fetchRequest.sortDescriptors = sortArray
fetchRequest.fetchBatchSize = 4
fetchRequest.predicate = predicate
let fetchedResultsController: NSFetchedResultsController<T> =
NSFetchedResultsController<T>(fetchRequest: fetchRequest, managedObjectContext: mainContext, sectionNameKeyPath: nil, cacheName: nil)
try fetchedResultsController.performFetch()
return fetchedResultsController
}
Then you can invoke it using:
if let frc: NSFetchedResultsController<SchoolDetails> = try? CD.FRCWith(sortArray: [], mainContext: moc) {
// Do something with results
if let schoolDetails = frc.fetchedObjects?.first {
// schoolDetails will be an instance of SchoolDetails
}
}
Note that I have declared the function as throws rather than hiding the error inside the function.
I was using a lazy var in table view controller to get the data from CoreData. It was working good in swift2. But When I upgraded to Swift3, Its showing an error as below. Kindly help me to change for Swift3
Error : Cannot convert value of type 'Error' to specified type 'NSFetchedResultsController'
lazy var fetchedResultsController: NSfetchedResultsController =
{
let fetchRequest = NSFetchRequest(entityName: "EvtIvtTbl")
let sortDescriptor = NSSortDescriptor(key: "bym_kol", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
let fetchedResultsController = NSfetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: self.managedObjectContext,
sectionNameKeyPath: nil,
cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
}()
In Swift 3.0, NSFetchedResultsController and NSFetchRequest want type parameters. Assuming that EvtIvtTbl is your NSManagedObject subclass, your code should look like this:
lazy var fetchedResultsController: NSFetchedResultsController<EvtIvtTbl> = {
let fetchRequest = NSFetchRequest<EvtIvtTbl>(entityName: "EvtIvtTbl")
let sortDescriptor = NSSortDescriptor(key: "bym_kol", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
let fetchedResultsController = NSFetchedResultsController<EvtIvtTbl>(fetchRequest: fetchRequest,
managedObjectContext: self.managedObjectContext,
sectionNameKeyPath: nil,
cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
}()
I can't get my NSFetchedResultsController initialized in iOS 10 using Swift 3 within CoreDataTableViewController from AECoreDataUI.
let request = NSFetchRequest<NasaPicture>(entityName:"NasaPicture")
request.predicate = Predicate(format: "isPagedResult == YES")
request.sortDescriptors = [SortDescriptor(key: "date", ascending: false)]
fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)
Compiler is complaining that
"Cannot convert value of type NSFetchedResultsController<NasaPicture> to expected type NSFetchedResultsController<_>"
The controller is now using generic type for swift, but it is not inferring the entity type correctly. I've tried explicitly:
fetchedResultsController = NSFetchedResultsController<NasaPicture>(fetchRequest: request, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)
No luck either.
Thanks!
NSFetchRequest is now a generic. NSFetchedResultsController is a generic too. Therefore, when declaring variables, you have to use a generic declaration, e.g.:
var fetchedResultsController: NSFetchedResultsController<NasaPicture>?
when we need to declare variable, then we have to use a generic declaration
please check below code for NSFetchedResultsController in swift 3..
override func viewDidLoad() {
super.viewDidLoad()
do {
try self.fetchedResultsController.performFetch()
} catch {
let fetchError = error as NSError
print("Unable to Perform Fetch Request")
print("\(fetchError), \(fetchError.localizedDescription)")
}
}
// MARK: - NSFetchedResultsController
fileprivate lazy var fetchedResultsController: NSFetchedResultsController<UserExistenceOnXMPPCD> = {
let fetchRequest = NSFetchRequest<UserExistenceOnXMPPCD>(entityName: "UserExistenceOnXMPPCD")
fetchRequest.sortDescriptors = [
NSSortDescriptor(key: "name", ascending: true)]
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext:CoreDataController.sharedInstance.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
try! fetchedResultsController.performFetch()
fetchedResultsController.delegate = self
if let quotes = fetchedResultsController.fetchedObjects {
if quotes.count > 0 {
print(quotes.count)
}
}
return fetchedResultsController
}()
// MARK: - NSFetchedResultsController delegate methods
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.reloadData()
}
Simply call the function:
private func setupFetchedResultsController() {
let context = NSManagedObjectContext.mr_default()
let fetchRequest = NSFetchRequest<Month>(entityName: "Month")
let dateDescriptor = NSSortDescriptor(key: "date", ascending: false)
fetchRequest.sortDescriptors = [dateDescriptor]
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: "year", cacheName: nil)
fetchedResultsController.delegate = self
try! fetchedResultsController.performFetch()
tableView.reloadData()
}
I want to load more cells when user in the last cell. I use CoreData and I get data from it. I use this answer to do what I want, but it didn't work. What problem can be there? Also I have one more question. I don't know why working only first implementation.
First implementation
var fetchedResultsController: NSFetchedResultsController {
let moc = DatabaseController.sharedInstance.managedObjectContext
let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Coctail", inManagedObjectContext: moc)
fetchRequest.entity = entity
fetchRequest.fetchLimit = 10
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: moc,
sectionNameKeyPath: nil,
cacheName: nil)
aFetchedResultsController.delegate = self
do {
try aFetchedResultsController.performFetch()
} catch {
fatalError("\(error)")
}
return aFetchedResultsController
}
Second Implementation
func initilizeFetchedResultsController() {
let moc = DatabaseController.sharedInstance.managedObjectContext
let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Coctail", inManagedObjectContext: moc)
fetchRequest.entity = entity
fetchRequest.fetchLimit = 10
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: moc,
sectionNameKeyPath: nil,
cacheName: nil)
aFetchedResultsController.delegate = self
do {
try aFetchedResultsController.performFetch()
} catch {
fatalError("\(error)")
}
fetchedResultsController = aFetchedResultsController
}
Hard to tell why the first solution but the second doesn't without seeing the other code that would have used the fetchedResultsController or called initilizeFetchedResultsController().
The reason you're not getting more data is that you've hardcoded your fetchLimit to 10. No matter what you do, you'll only ever get 10 results.
You'll need to change the fetchLimit to get more data. Check out this answer -- it is similar to what you'll need to do: https://stackoverflow.com/a/6786931/5605379
On compile this code:
func managedObjectContext_roster() -> NSManagedObjectContext {
return Messenger.sharedInstance.xmppRosterStorage!.mainThreadManagedObjectContext
}
I get the next error:
CoreData: error: Failed to call designated initializer on NSManagedObject class 'XMPPUserCoreDataStorageObject'
What this error means and how can I fix it? I searched in Google, but did not find anything
UPDATE
func fetchedResultsController() -> NSFetchedResultsController? {
if fetchedResultsControllerVar == nil {
let moc = MessengerRoster.sharedInstance.managedObjectContext_roster() as NSManagedObjectContext?
let entity = NSEntityDescription.entityForName("XMPPUserCoreDataStorageObject", inManagedObjectContext: moc!)
let sd1 = NSSortDescriptor(key: "sectionNum", ascending: true)
let sd2 = NSSortDescriptor(key: "displayName", ascending: true)
let sortDescriptors = [sd1, sd2]
let fetchRequest = NSFetchRequest()
fetchRequest.entity = entity
fetchRequest.sortDescriptors = sortDescriptors
fetchRequest.fetchBatchSize = 10
fetchedResultsControllerVar = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc!, sectionNameKeyPath: "sectionNum", cacheName: nil)
fetchedResultsControllerVar?.delegate = self
if fetchedResultsControllerVar?.performFetch(nil) == nil {
//Handle fetch error
}
}
return fetchedResultsControllerVar!
}