无法将图像加载到核心数据中的相册
trouble loading images to photo album in core data
我在核心数据中设置了一对多关系
一个相册可以保存多张图片
每次我创建新相册时,都会加载相同的图像。我希望用户能够将不同的照片保存到每个相册
我认为问题可能出在我尝试加载数据时的谓词上,但我不完全确定。很抱歉 post 使用所有这些可能不相关的代码,但我想 post 所有代码以防万一我没有看到其他人可能会捕捉到的东西。
我还想补充一点,当我添加 NSPredicate 的代码时,当我单击相册单元格时,集合视图中没有图像显示,但是当我在 loadData() 中注释掉谓词的代码时,图像显示。我不知道为什么会这样。
class ViewController: UIViewController {
var fetchedResultsController: NSFetchedResultsController<PhotoAlbum>!
var contextApp = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var moc:NSManagedObjectContext! = nil
@IBOutlet weak var tableView: UITableView!
func setupFetchedResultsController() {
let fetchRequest:NSFetchRequest<PhotoAlbum> = PhotoAlbum.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "album", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: contextApp, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = self
do {
try fetchedResultsController.performFetch()
}catch {
print(error)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.delegate = self
tableView.dataSource = self
setupFetchedResultsController()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupFetchedResultsController()
}
@IBAction func createNewAlbum(_ sender: UIBarButtonItem) {
presentnewAlbumAlert()
}
func presentnewAlbumAlert () {
let alert = UIAlertController(title: "New Album", message: "Enter a name for this album", preferredStyle: .alert)
// Create actions
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let saveAction = UIAlertAction(title: "Save", style: .default) { [weak self] action in
if let name = alert.textFields?.first?.text {
self?.addAlbumCell(name: name)
}
}
saveAction.isEnabled = false
// Add a text field
alert.addTextField { textField in
textField.placeholder = "Name"
NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: textField, queue: .main) { notif in
if let text = textField.text, !text.isEmpty {
saveAction.isEnabled = true
} else {
saveAction.isEnabled = false
}
}
}
alert.addAction(cancelAction)
alert.addAction(saveAction)
present(alert, animated: true, completion: nil)
}
func addAlbumCell(name: String) {
let album = PhotoAlbum(context: contextApp)
album.album = name
do {
try contextApp.save()
}catch{
print(error)
}
}
func deleteNote(at indexPath: IndexPath) {
let albumToDelete = fetchedResultsController.object(at: indexPath)
contextApp.delete(albumToDelete)
try? contextApp.save()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toCollection" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = fetchedResultsController.object(at: indexPath)
(segue.destination as! PhotoViewController).album = object
}
}
}
}
// 标记:数据源
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section:
Int) -> Int {
return fetchedResultsController?.sections![section].numberOfObjects
?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let aNewalbum = fetchedResultsController.object(at: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "toCollection", for: indexPath)
cell.textLabel?.text = aNewalbum.album
return cell
}
}
// 标记:DELGEATE
extension ViewController : UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController?.sections?.count ?? 1
}
}
// SETUP NSFetchedResultsControllerDelegate
extension ViewController : NSFetchedResultsControllerDelegate {
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete :
tableView.deleteRows(at: [indexPath!], with: .fade)
default:
break
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
let indexSet = IndexSet(integer: sectionIndex)
switch type {
case .insert:
tableView.insertSections(indexSet, with: .fade)
case .delete :
tableView.deleteSections(indexSet, with: .fade)
default:
break
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
tableView.reloadData()
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
tableView.reloadData()
}
}
集合视图的代码
class PhotoViewController: UIViewController , UICollectionViewDelegate , UICollectionViewDataSource , UICollectionViewDelegateFlowLayout , UIImagePickerControllerDelegate , UINavigationControllerDelegate {
var imageDataArray = [Images]()
var imageArray = [UIImage]()
var managedObjectContext:NSManagedObjectContext!
var mySelection:Int?
var album: PhotoAlbum!
@IBOutlet var collectionView: UICollectionView!
@IBAction func addImage(_ sender: Any) {
let picker:UIImagePickerController = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
picker.delegate = self
picker.allowsEditing = false
self.present(picker, animated: true, completion: nil)
}
// Setup the collection view
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: imageCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "thumbnail", for: indexPath) as! imageCollectionViewCell
let imageItem = imageDataArray[indexPath.row]
if let presentImage = UIImage(data: (imageItem.images as! Data) ){
cell.chosenImage.image = presentImage
mySelection = indexPath.row
imageArray.append(presentImage)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageDataArray.count
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let pickedImage = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) {
picker.dismiss(animated: true) {
self.createImageContext(with: pickedImage)
self.imageArray.append(pickedImage)
}
}
}
// 加载和保存图像
func loadData() {
let imageReqeust: NSFetchRequest<Images> = Images.fetchRequest()
let predicate = NSPredicate(format: "images.album == %@", album)
imageReqeust.predicate = predicate
// print(predicate.description)
do {
imageDataArray = try managedObjectContext.fetch(imageReqeust)
self.collectionView.reloadData()
}catch {
print("Could not load data from database \(error.localizedDescription)")
}
}
func createImageContext( with image: UIImage) {
let imageItem = Images(context: managedObjectContext!)
imageItem.images = NSData(data: image.jpegData(compressionQuality: 1.0)!) as Data
// imageItem.image = NSData(data: UIImageJPEGRepresentation(image, 0.3)!) as Data
do {
try self.managedObjectContext.save()
self.loadData()
}catch {
print("Could not save data \(error.localizedDescription)")
}
}
// ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addImage(_:)))
loadData()
// Do any additional setup after loading the view.
}
在您的第二个视图控制器中,您不需要从核心数据中获取图像,而是可以通过您的相册访问它们 属性。
imageDataArray = Array(album.images)
保存新图像实例时,不要忘记将其分配到相册
imageItem.album = self.album
我在核心数据中设置了一对多关系
一个相册可以保存多张图片
每次我创建新相册时,都会加载相同的图像。我希望用户能够将不同的照片保存到每个相册
我认为问题可能出在我尝试加载数据时的谓词上,但我不完全确定。很抱歉 post 使用所有这些可能不相关的代码,但我想 post 所有代码以防万一我没有看到其他人可能会捕捉到的东西。
我还想补充一点,当我添加 NSPredicate 的代码时,当我单击相册单元格时,集合视图中没有图像显示,但是当我在 loadData() 中注释掉谓词的代码时,图像显示。我不知道为什么会这样。
class ViewController: UIViewController {
var fetchedResultsController: NSFetchedResultsController<PhotoAlbum>!
var contextApp = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var moc:NSManagedObjectContext! = nil
@IBOutlet weak var tableView: UITableView!
func setupFetchedResultsController() {
let fetchRequest:NSFetchRequest<PhotoAlbum> = PhotoAlbum.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "album", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: contextApp, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = self
do {
try fetchedResultsController.performFetch()
}catch {
print(error)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.delegate = self
tableView.dataSource = self
setupFetchedResultsController()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupFetchedResultsController()
}
@IBAction func createNewAlbum(_ sender: UIBarButtonItem) {
presentnewAlbumAlert()
}
func presentnewAlbumAlert () {
let alert = UIAlertController(title: "New Album", message: "Enter a name for this album", preferredStyle: .alert)
// Create actions
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let saveAction = UIAlertAction(title: "Save", style: .default) { [weak self] action in
if let name = alert.textFields?.first?.text {
self?.addAlbumCell(name: name)
}
}
saveAction.isEnabled = false
// Add a text field
alert.addTextField { textField in
textField.placeholder = "Name"
NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: textField, queue: .main) { notif in
if let text = textField.text, !text.isEmpty {
saveAction.isEnabled = true
} else {
saveAction.isEnabled = false
}
}
}
alert.addAction(cancelAction)
alert.addAction(saveAction)
present(alert, animated: true, completion: nil)
}
func addAlbumCell(name: String) {
let album = PhotoAlbum(context: contextApp)
album.album = name
do {
try contextApp.save()
}catch{
print(error)
}
}
func deleteNote(at indexPath: IndexPath) {
let albumToDelete = fetchedResultsController.object(at: indexPath)
contextApp.delete(albumToDelete)
try? contextApp.save()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toCollection" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = fetchedResultsController.object(at: indexPath)
(segue.destination as! PhotoViewController).album = object
}
}
}
} // 标记:数据源
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section:
Int) -> Int {
return fetchedResultsController?.sections![section].numberOfObjects
?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let aNewalbum = fetchedResultsController.object(at: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "toCollection", for: indexPath)
cell.textLabel?.text = aNewalbum.album
return cell
}
}
// 标记:DELGEATE
extension ViewController : UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController?.sections?.count ?? 1
}
}
// SETUP NSFetchedResultsControllerDelegate
extension ViewController : NSFetchedResultsControllerDelegate {
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete :
tableView.deleteRows(at: [indexPath!], with: .fade)
default:
break
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
let indexSet = IndexSet(integer: sectionIndex)
switch type {
case .insert:
tableView.insertSections(indexSet, with: .fade)
case .delete :
tableView.deleteSections(indexSet, with: .fade)
default:
break
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
tableView.reloadData()
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
tableView.reloadData()
}
}
集合视图的代码
class PhotoViewController: UIViewController , UICollectionViewDelegate , UICollectionViewDataSource , UICollectionViewDelegateFlowLayout , UIImagePickerControllerDelegate , UINavigationControllerDelegate {
var imageDataArray = [Images]()
var imageArray = [UIImage]()
var managedObjectContext:NSManagedObjectContext!
var mySelection:Int?
var album: PhotoAlbum!
@IBOutlet var collectionView: UICollectionView!
@IBAction func addImage(_ sender: Any) {
let picker:UIImagePickerController = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
picker.delegate = self
picker.allowsEditing = false
self.present(picker, animated: true, completion: nil)
}
// Setup the collection view
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: imageCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "thumbnail", for: indexPath) as! imageCollectionViewCell
let imageItem = imageDataArray[indexPath.row]
if let presentImage = UIImage(data: (imageItem.images as! Data) ){
cell.chosenImage.image = presentImage
mySelection = indexPath.row
imageArray.append(presentImage)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageDataArray.count
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let pickedImage = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) {
picker.dismiss(animated: true) {
self.createImageContext(with: pickedImage)
self.imageArray.append(pickedImage)
}
}
}
// 加载和保存图像
func loadData() {
let imageReqeust: NSFetchRequest<Images> = Images.fetchRequest()
let predicate = NSPredicate(format: "images.album == %@", album)
imageReqeust.predicate = predicate
// print(predicate.description)
do {
imageDataArray = try managedObjectContext.fetch(imageReqeust)
self.collectionView.reloadData()
}catch {
print("Could not load data from database \(error.localizedDescription)")
}
}
func createImageContext( with image: UIImage) {
let imageItem = Images(context: managedObjectContext!)
imageItem.images = NSData(data: image.jpegData(compressionQuality: 1.0)!) as Data
// imageItem.image = NSData(data: UIImageJPEGRepresentation(image, 0.3)!) as Data
do {
try self.managedObjectContext.save()
self.loadData()
}catch {
print("Could not save data \(error.localizedDescription)")
}
}
// ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addImage(_:)))
loadData()
// Do any additional setup after loading the view.
}
在您的第二个视图控制器中,您不需要从核心数据中获取图像,而是可以通过您的相册访问它们 属性。
imageDataArray = Array(album.images)
保存新图像实例时,不要忘记将其分配到相册
imageItem.album = self.album