如何将 imageData 保存到 NSManagedObject 属性

Posted

技术标签:

【中文标题】如何将 imageData 保存到 NSManagedObject 属性【英文标题】:How to save imageData to NSManagedObject property 【发布时间】:2018-01-23 02:51:34 【问题描述】:

我的应用程序从 Flickr 下载图像并将它们显示在 CollectionViewController 中,并将图像保存在 Core Data 中。我正在尝试将 imageData 保存到我的 NSManagedObject 上下文中,但我可以说我没有正确执行此操作,因为我从未在 cellForRowAt 函数中进入逻辑的“其他”部分。在哪里以及如何使用 imageData 属性更新我的“图像”NSManagedObject?

这是我的客户端类:

    func getImagesFromFlickr(pin: Pin, context: NSManagedObjectContext, page: Any, completionHandlerForGetImages: @escaping (_ success: Bool, _ errorString: String?) -> Void) 

    let methodParameters = [
        Constants.FlickrParameterKeys.Method: Constants.FlickrParameterValues.FlickrPhotosSearch,
        Constants.FlickrParameterKeys.APIKey: Constants.FlickrParameterValues.APIKey,
        Constants.FlickrParameterKeys.Format: Constants.FlickrParameterValues.ResponseFormat,
        Constants.FlickrParameterKeys.Extras: Constants.FlickrParameterValues.MediumURL,
        Constants.FlickrParameterKeys.NoJSONCallback: Constants.FlickrParameterValues.DisableJSONCallback,
        Constants.FlickrParameterKeys.Lat: pin.latitude as Any,
        Constants.FlickrParameterKeys.Lon: pin.longitude as Any,
        Constants.FlickrParameterKeys.PerPage: Constants.FlickrParameterValues.PerPage,
        Constants.FlickrParameterKeys.Page: page
    ]

    taskForGetImages(methodParameters: methodParameters, latitude: pin.latitude, longitude: pin.longitude)  (results, error) in

        if let error = error 
            completionHandlerForGetImages(false, "There was an error getting the images: \(error)")
         else 

            // Create a dictionary from the data:

            /* GUARD: Are the "photos" and "photo" keys in our result? */
            if let photosDictionary = results![Constants.FlickrResponseKeys.Photos] as? [String:AnyObject], let photoArray = photosDictionary[Constants.FlickrResponseKeys.Photo] as? [[String:AnyObject]] 

                for photo in photoArray 

                    let image = Images(context: CoreDataStack.sharedInstance().context)

                    // GUARD: Does our photo have a key for 'url_m'?
                    guard let imageUrlString = photo[Constants.FlickrResponseKeys.MediumURL] as? String else 
                        completionHandlerForGetImages(false, "Unable to find key '\(Constants.FlickrResponseKeys.MediumURL)' in \(photo)")
                        return
                    

                    // Get metadata
                    let imageURL = URL(string: imageUrlString)!
                    let title = photo["title"] as? String ?? ""

                    // Assign the metadata to images NSManagedObject
                    image.imageURL = String(describing: imageURL)
                    image.pin = pin
                    image.title = title

                    CoreDataStack.sharedInstance().context.insert(image)
                
                CoreDataStack.sharedInstance().saveContext()
            
            completionHandlerForGetImages(true, nil)
        
    


func withBigImage(_ urlString: String?, completionHandler handler: @escaping (_ image:UIImage) -> Void)

    DispatchQueue.global(qos: .userInitiated).async  () -> Void in

        if let url = URL(string: urlString!) 
            if let imgData = try? Data(contentsOf: url) 
                if let img = UIImage(data: imgData) 

                    performUIUpdatesOnMain 
                        let image = Images(context: CoreDataStack.sharedInstance().context)
                        image.imageData = imgData as NSData
                        CoreDataStack.sharedInstance().saveContext()
                    

                    performUIUpdatesOnMain 
                        handler(img)
                    
                
            
        
    

还有我的 cellForItemAt 方法:

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath as IndexPath) as! CollectionViewCell

    cell.activityIndicator.hidesWhenStopped = true
    cell.activityIndicator.activityIndicatorViewStyle = .whiteLarge
    cell.activityIndicator.center = CGPoint(x: cell.frame.size.width/2, y: cell.frame.size.height/2)

    performUIUpdatesOnMain 
        cell.activityIndicator.startAnimating()
    
    let image = self.fetchedResultsController.object(at: indexPath)

    if image.imageData == nil 
        print("Image data doesn't exist")

        FlickrClient.sharedInstance().withBigImage(image.imageURL, completionHandler:  (cellImage) in

            performUIUpdatesOnMain 
                cell.imageView.image = cellImage
                cell.activityIndicator.stopAnimating()
            
        )
     else 
        print("Image data exists")
        performUIUpdatesOnMain 
            cell.imageView.image = image.image
            cell.activityIndicator.stopAnimating()
        
    

    if let _ = self.selectedIndexes.index(of: indexPath) 
        cell.imageView.alpha = 0.5
     else 
        cell.imageView.alpha = 1.0
    
    return cell

*注意: performUIUpdatesOnMain 是我的 GCD DispatchQueue.main.async 方法。

我认为这可能是后台和主队列问题的问题,但我不确定如何解决。

【问题讨论】:

【参考方案1】:

如果图像数据被存储,您是否检查过您的 sqlite 数据库?如果您正在使用模拟器,则可以使用DB Browser for SQLite。 您真的需要将图像存储在 coredata 中吗,更好的方法是仅将图像路径/元数据存储在 coredata 中,并将纯图像存储在文件系统中。

无论如何。如果sqlite数据库没有数据写入,可以尝试使用UIImageJPEGRepresentation转换图片并保存转换后的数据

let imgData = UIImageJPEGRepresentation(img!, 1)

【讨论】:

我正在为一个类制作这个应用程序,并将 imageData 保存在 Core Data 中是一项要求。实际上,我已经让它与除该功能之外的所有功能一起使用。我见过你上面提到的这种方法......是建议我应该下载imageData,将其转换为UIImage,然后将UIImage转回imageData以保存它?当我第一次从 URL 中提取 imageData 时,似乎我应该能够将 imageData 保存到 Core Data,不是吗?

以上是关于如何将 imageData 保存到 NSManagedObject 属性的主要内容,如果未能解决你的问题,请参考以下文章

C#怎样将数组作为文件流保存起来

将图像控件转换为字节数组 Asp.Net

将UIImage转换为NSData并在Swift中转换回UIImage?

delphi 中如何将图片数据保存到dat文件里的,然后读取出来,并在Image控件中显示。

如何将图像存储到 UIImage 数组(Swift)

如何在不复制的情况下将画布 imageData 传递给 emscripten c++ 程序?