iOS 8 Swift:使用 segue 编辑 NSManagedObject:声明类型时出错

Posted

技术标签:

【中文标题】iOS 8 Swift:使用 segue 编辑 NSManagedObject:声明类型时出错【英文标题】:iOS 8 Swift: editing NSManagedObject with segue: error when declaring types 【发布时间】:2015-04-18 00:01:27 【问题描述】:

所以我在思考如何在 Core Data 中编辑/更新对象时遇到了一些麻烦。

我想要做的是在我的DetailViewController 中有两个 segues 推送到我的AddTableViewController

DetailViewController:

import UIKit
import Social
import CoreData



class DetailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate 
    @IBOutlet var backpackerSpotImageView:UIImageView!
    @IBOutlet var tableView:UITableView!


    var backpackerSpot:BackpackerSpot?
    var managedContext: NSManagedObjectContext!

    var backpackerSpots:[BackpackerSpot] = []

    var fetchResultController:NSFetchedResultsController!


    override func viewDidLoad() 
        super.viewDidLoad()

        // customizing background of tableview
        self.tableView.backgroundColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.2)

        // remove extra separators
        self.tableView.tableFooterView = UIView(frame: CGRectZero)

        // change the color of the separator
        self.tableView.separatorColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.8)

        // self-sizing cells
        tableView.estimatedRowHeight = 36.0
        tableView.rowHeight = UITableViewAutomaticDimension

        // Do any additional setup after loading the view.
        if let spotImage = backpackerSpot?.spotImage
        
        self.backpackerSpotImageView.image = UIImage(data:spotImage)
        
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return 4
    

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 


        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! DetailTableViewCell

        // make cell transparent so background color can be seen
        cell.backgroundColor = UIColor.clearColor()

        cell.mapButton.hidden = true

        switch indexPath.row 
        case 0:
            cell.fieldLabel.text = "Name"
            cell.valueLabel.text = backpackerSpot?.spotName
        case 1:
            cell.fieldLabel.text = "Location"
            cell.valueLabel.text = backpackerSpot?.spotLocation
            cell.mapButton.hidden = false
        case 2:
            cell.fieldLabel.text = "Notes"
            cell.valueLabel.text = backpackerSpot?.spotNote
        default:
            cell.fieldLabel.text = ""
            cell.valueLabel.text = ""

        

        return cell
    

//    func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool 
//        return true
//    
//    
//    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) 
//        if(editingStyle == .Delete) 
//            // Find the BackPacker Spot object the user is trying to delete
//            let backpackerSpotToDelete = backpackerSpots[indexPath.row]
//            
//            // Delete it from the managedObjectContext
//            managedContext?.deleteObject(backpackerSpotToDelete)
//            
//           reloadInputViews()
//            
//
//        
//    

    @IBAction func shareSheet(sender:UIBarButtonItem) 
        let firstActivityItem = backpackerSpot!.spotName
        let secondActivityItem = backpackerSpot!.spotLocation

        let activityViewController : UIActivityViewController = UIActivityViewController(
            activityItems: [firstActivityItem, secondActivityItem], applicationActivities: nil)

        activityViewController.excludedActivityTypes = [
            UIActivityTypePostToVimeo,
            UIActivityTypePostToTencentWeibo,
            UIActivityTypePostToFlickr,
            UIActivityTypePostToWeibo,
            UIActivityTypeSaveToCameraRoll,
            UIActivityTypePrint,
            UIActivityTypeAssignToContact,
            UIActivityTypeAddToReadingList
        ]

        self.presentViewController(activityViewController, animated: true, completion: nil)

    

    // MARK: - Navigation

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 

        if segue.identifier == "showMap" 
            let destinationController = segue.destinationViewController as! MapViewController
            destinationController.backpackerSpot = backpackerSpot
         else if segue.identifier == "editSpot"
            var selectedItem: NSManagedObject = backpackerSpot!
            let destinationController = segue.destinationViewController as! AddTableViewController

            destinationController.existingName = selectedItem.valueForKey("spotName") as! String
            destinationController.existingLocation = selectedItem.valueForKey("spotLocation") as! String
            destinationController.existingNotes = selectedItem.valueForKey("spotNote") as! String
            destinationController.existingImage = selectedItem.valueForKey("spotImage") as! NSData
            destinationController.existingSpot = selectedItem
            destinationController.backpackerSpot = backpackerSpot

            
        

    

AddTableViewController:

import UIKit
import CoreData

class AddTableViewController: UITableViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate 

    @IBOutlet weak var nameTextField:UITextField!
    @IBOutlet weak var locationTextField:UITextField!
    @IBOutlet weak var imageView:UIImageView!
    @IBOutlet weak var notesView:UITextView!

    var existingName:String = ""
    var existingLocation:String = ""
    var existingNotes:String = ""
    var existingImage:NSData!
    var existingSpot: NSManagedObject!


    var coreDataStack = (UIApplication.sharedApplication().delegate as! AppDelegate).coreDataStack

    var backpackerSpot:BackpackerSpot!
    var managedContext: NSManagedObjectContext!

    override func viewDidLoad() 
        super.viewDidLoad()
        managedContext = coreDataStack.context

        if (existingSpot != nil) 
            nameTextField.text = existingName
            locationTextField.text = existingLocation
            imageView.image = existingImage
            notesView.text = existingNotes
        
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.

    

    // TODO Give user the choice of the Photo Library or the Camera
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
        if indexPath.row == 0 
            if UIImagePickerController.isSourceTypeAvailable(.Camera) 
                let imagePicker = UIImagePickerController()
                imagePicker.allowsEditing = false
                imagePicker.delegate = self
                imagePicker.sourceType = .Camera

                self.presentViewController(imagePicker, animated: true, completion: nil)
            
        

        tableView.deselectRowAtIndexPath(indexPath, animated: true)
    

    // FIXME image is being displayed in landscape if it is taken in portrait mode by default
    func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) 
        imageView.image = image
        imageView.contentMode = UIViewContentMode.ScaleAspectFill
        imageView.clipsToBounds = true

        dismissViewControllerAnimated(true, completion: nil)
    

    @IBAction func save() 

        //validation
        var errorField = ""

        // TODO have placeholder text in the NOTES field match up with the placholder text in the NAME and LOCATION fields.
        if nameTextField.text == "" 
            errorField = "name"
         else if locationTextField.text == "" 
            errorField = "location"
         else if notesView.text == "" 
            errorField = "notes"
        

        if errorField != "" 

            let alertController = UIAlertController(title: "Error", message: "You must fill in \(errorField).", preferredStyle: .Alert)
            let doneAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
            alertController.addAction(doneAction)

            self.presentViewController(alertController, animated: true, completion: nil)

            return
        

        // If all fields are correctly filled in, extract the field value
        // Create Restaurant Object and save to data store
//        if let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).coreDataStack.context 

            let entityBackpackerSpot = NSEntityDescription.entityForName("BackpackerSpot", inManagedObjectContext: coreDataStack.context)

            backpackerSpot = BackpackerSpot( entity: entityBackpackerSpot!, insertIntoManagedObjectContext: managedContext )

            backpackerSpot?.spotName = nameTextField.text
            backpackerSpot?.spotLocation = locationTextField.text
            backpackerSpot?.spotImage = UIImagePNGRepresentation(imageView.image)
            backpackerSpot?.spotNote = notesView.text

            var error: NSError?
            if !managedContext.save(&error) 
                println("insert error: \(error!.localizedDescription)")
                return
            

        // Execute the unwind segue and go back to the home screen
        performSegueWithIdentifier("unwindToHomeScreen", sender: self)
    


我知道我还没有必要的功能来编辑我的AddTableViewController 中的数据,但我遇到的第一个问题甚至是传递数据。我目前收到以下错误:

AddTableViewController.swift:38:31: Cannot assign a value of type 'NSData!' to a value of type 'UIImage?'

我尝试将相同的变量强制转换为 UIImage,但这也给了我一个错误(这是我所预料的)。

我是在正确的轨道上,还是应该以完全不同的方式编辑/更新对象?我已经使用 CoreData 工作了几个星期,并且开始掌握它的窍门,但正如我之前所说,我无法完全解决传递数据的问题。

感谢任何帮助。谢谢。

【问题讨论】:

【参考方案1】:

你需要先用你的 NSData 创建 UIImage,试试:

if (existingSpot != nil) 
        nameTextField.text = existingName
        locationTextField.text = existingLocation
        imageView.image = UIImage(data: existingImage)
        notesView.text = existingNotes
    

【讨论】:

谢谢。做到了:)。

以上是关于iOS 8 Swift:使用 segue 编辑 NSManagedObject:声明类型时出错的主要内容,如果未能解决你的问题,请参考以下文章

准备使用数组进行 Segue - Xcode 8.0 Swift 3.0

如何使用 Swift 在 iOS 中以编程方式进行 segue

无法使用 Xcode 8 和 Swift 3 在 SpriteKit 中以编程方式触发 segue

iOS Swift 使用 Segue 在 vi​​ewController 之间传递变量

自定义幻灯片 Segue - Xcode 8.0 Swift 3.0

Swift:如果条件不满足,则继续执行 segue