Closed andriyslyusar closed 9 years ago
Workaround: stay with Objective-C! IMHO, Swift is not mature enough yet...
Andrey Slyusar wrote:
I tried to migrate my project to xCode 6.3 with swift 1.2 support. But I start to experience strange issue:
- I am creating and updating new Core Data objects:
private lazyvar moc: NSManagedObjectContext= { return NSManagedObjectContext.MR_context(); }()
- In code I create new objects in 'moc'
- As a final step
moc.MR_saveToPersistentStoreAndWait()
In another place I have a UITableViewControoler with NSFetchedResultsControllerDelegate, but none of delegates fire after migration to xCode 6.3. Rolling back to swift 1.1 in xCode 6.1.1 everything works as expected.
Can anybody confirm the same behaviour? Or maybe any ideas why it can happen and possible workaround ?
— Reply to this email directly or view it on GitHub https://github.com/magicalpanda/MagicalRecord/issues/963.
It is already to late to switch back to ObjC, too many code in swift to rewrite. It just working in xCode 6.1.1 without incremental updates is very painful, but without solving this issue I will need to rollback from swift 1.2 to 1.1.
It would be wise to play with Swift 1.2, but not commit to it until later in the seed cycle for Xcode 6.3. The beta we have right now seems to have some glaring bugs, many of which Apple engineers have acknowledged they are working on fixing for Swift 1.2's actual release.
Keep an eye on this issue all the same — if it comes up later in the seeds of Xcode 6.3, I'll need to look at fixing it.
I try to reimplement similar logic without MagicRecord and delegate method is called. Swift 1.2 has incremental updates and this is a great benefit for pure swift project >300 classes. I will spent some time trying to find by myself or switch to stable xCode. Maybe you have any idea why it could happen?
class ViewController: UIViewController, UITableViewDataSource, NSFetchedResultsControllerDelegate {
@IBOutlet weak var tableView: UITableView!
var fetchedResultsController: NSFetchedResultsController!
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
lazy var managedContext: NSManagedObjectContext = {
return self.appDelegate.managedObjectContext!
}()
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let fetchRequest = NSFetchRequest(entityName: "Person")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: appDelegate.managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
self.fetchedResultsController.delegate = self
var error: NSError?
fetchedResultsController.performFetch(&error)
tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
// MARK: UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController.fetchedObjects!.count
}
func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell
let person = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
cell.textLabel!.text = person.valueForKey("name") as! String?
return cell
}
//Implement the addName IBAction
@IBAction func addName(sender: AnyObject) {
var alert = UIAlertController(title: "New name", message: "Add a new name", preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Save", style: .Default) { (action: UIAlertAction!) -> Void in
let textField = alert.textFields![0] as! UITextField
self.saveName(textField.text)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .Default) { (action: UIAlertAction!) -> Void in
}
alert.addTextFieldWithConfigurationHandler {
(textField: UITextField!) -> Void in
}
alert.addAction(saveAction)
alert.addAction(cancelAction)
presentViewController(alert, animated: true, completion: nil)
}
func saveName(name: String) {
//2
let entity = NSEntityDescription.entityForName("Person", inManagedObjectContext: managedContext)
let person = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)
//3
person.setValue(name, forKey: "name")
//4
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
}
// ========================================
// MARK: - NSFetchedResultsController
// ========================================
func controllerWillChangeContent(controller: NSFetchedResultsController) {
tableView.beginUpdates()
}
}
I found a possible cure for this.
1) Be sure that you have implemented -controllerDidChangeContent
(even if empty), otherwise the fetchedResultsController track-changes will not be enabled (per docs).
2) Set the @objc
directive on -controllerDidChangeContent
and other NSFetchedResultsControllerDelegate methods, so the FRC can 'see' them (as it's an ObjC class).
I was having this problem and #2 above saved the day. Still fighting various other weird bugs, but that was by far the worst.
@davetroy Thanks for response.
-controllerDidChangeContent
: func controllerDidChangeContent(controller: NSFetchedResultsController) {
if ignoreNextUpdates {
ignoreNextUpdates = false
} else {
tableView.endUpdates()
}
}
@objc
could be a case, but I had the issue only in case I implement delegate methods as a part of private extension. I cannot verify it now for the reason we switch to xCode 6.2 and wait for official release of xCode 6.3 (we need to make beta build to iTunes)Adding @objc seemed to fix the issue for me as well. Thanks for the help. I was using Xcode 6.3, Swift 1.2.
Confirm. Thanks a lot for help. Does anybody now the reason we need to add @objc
?
It seems that this is a behavior change in Swift 1.2: methods in non-Objective-C-derived classes will no longer be implicitly marked @objc even if they match an Objective-C protocol. You can explicitly mark the methods with the @objc attribute if you don't want to extend NSObject. This is described in the Xcode 6.3 release notes at https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html#//apple_ref/doc/uid/TP40001051-CH4-SW3.
I tried to migrate my project to xCode 6.3 with swift 1.2 support. But I start to experience strange issue:
In another place I have a UITableViewControoler with NSFetchedResultsControllerDelegate, but none of delegates fire after migration to xCode 6.3. Rolling back to swift 1.1 in xCode 6.1.1 everything works as expected.
Can anybody confirm the same behaviour? Or maybe any ideas why it can happen and possible workaround ?