当我使用核心数据保存从collectionView单元格中下载的一些图像时,我收到错误'NSInternalInconsistencyException',原因:' - [UICollectionViewController loadView]加载了“BYZ-38-t0r-view-8bC- Xf-vdC“nib但没有获得UICollectionView。” 有我的albumViewController代码:
class albumViewController: coreDataCollectionViewController, MKMapViewDelegate {
// Properties
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var albumCollection: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.albumCollection.dataSource = self
self.albumCollection.delegate = self
// Show the pin
let spanLevel: CLLocationDistance = 2000
self.mapView.setRegion(MKCoordinateRegionMakeWithDistance(pinLocation.pinCoordinate, spanLevel, spanLevel), animated: true)
self.mapView.addAnnotation(pinLocation.pinAnnotation)
// Set the title
title = "Photo Album"
//Get the stack
let delegate = UIApplication.shared.delegate as! AppDelegate
let stack = delegate.stack
// Create a fetchrequest
let fr = NSFetchRequest<NSFetchRequestResult>(entityName: "Album")
fr.sortDescriptors = [NSSortDescriptor(key: "imageData", ascending: false),NSSortDescriptor(key: "creationDate", ascending: false)]
// Create the FetchedResultsController
fetchedResultsController = NSFetchedResultsController(fetchRequest: fr, managedObjectContext: stack.context, sectionNameKeyPath: nil, cacheName: nil)
// Put photos in core data
let photoURLs = Constants.photosUrl
for photoUrLString in photoURLs {
let photoURL = URL(string: photoUrLString)
if let photoData = try? Data(contentsOf: photoURL!) {
let photo = Album(imageData: photoData, context: fetchedResultsController!.managedObjectContext)
} else {
print("Image does not exist at \(photoURL)")
}
}
}
// Find number of items
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 9
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCollectionViewCell", for: indexPath) as! photoCollectionViewCell
let album = fetchedResultsController!.object(at: indexPath) as! Album
performUIUpdatesOnMain {
cell.photoImageView?.image = UIImage(data: album.imageData as! Data)
}
return cell
}
// Reload photos album
@IBAction func loadNewPhotos(_ sender: AnyObject) {
}
}
我的代码是
class coreDataCollectionViewController: UICollectionViewController {
// Mark: Properties
var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>? {
didSet {
// Whenever the frc changes, we execute the search and
// reload the table
fetchedResultsController?.delegate = self
executeSearch()
collectionView?.reloadData()
}
}
// Mark: Initializers
init(fetchedResultsController fc: NSFetchedResultsController<NSFetchRequestResult>, collectionViewLayout: UICollectionViewFlowLayout) {
fetchedResultsController = fc
super.init(collectionViewLayout: collectionViewLayout)
}
// Do not worry about this initializer. I has to be implemented because of the way Swift interfaces with an Objective C protocol called NSArchiving. It's not relevant.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
// Mark: CoreDataTableViewController (Subclass Must Implement)
extension coreDataCollectionViewController {
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
fatalError("This method MUST be implemented by a subclass of CoreDataTableViewController")
}
}
// Mark: CoreDataTableViewController (Table Data Source)
extension coreDataCollectionViewController {
override func numberOfSections(in collectionView: UICollectionView) -> Int {
if let fc = fetchedResultsController {
return (fc.sections?.count)!
} else {
return 0
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let fc = fetchedResultsController {
return fc.sections![section].numberOfObjects
} else {
return 0
}
}
}
// Mark: CoreDataTableViewController (Fetches)
extension coreDataCollectionViewController {
func executeSearch() {
if let fc = fetchedResultsController {
do {
try fc.performFetch()
} catch let error as NSError {
print("Error while trying to perform a search: \n\(error)\n\(fetchedResultsController)")
}
}
}
}
// MARK: - CoreDataTableViewController: NSFetchedResultsControllerDelegate
extension coreDataCollectionViewController: NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
}
}
但如果我不使用核心数据,我就会成功。有什么不同吗?
class albumViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, MKMapViewDelegate {
// Properties
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var albumCollection: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let spanLevel: CLLocationDistance = 2000
self.mapView.setRegion(MKCoordinateRegionMakeWithDistance(location.pinCoordinate, spanLevel, spanLevel), animated: true)
self.mapView.addAnnotation(location.pinAnnotation)
}
// Find number of items
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Constants.photosUrl.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCollectionViewCell", for: indexPath) as! photoCollectionViewCell
let photoURL = URL(string: Constants.photosUrl[(indexPath as NSIndexPath).item])
if let photoData = try? Data(contentsOf: photoURL!) {
performUIUpdatesOnMain {
cell.photoImageView?.image = UIImage(data: photoData)
}
} else {
print("Image does not exist at \(photoURL)")
}
return cell
}
// Reload photos album
@IBAction func loadNewPhotos(_ sender: AnyObject) {
}
}
顺便说一句,有我的代码链接 https://github.com/MartinSnow/MyVirtualTourist.git 我的项目在“storeLocation”分支上。
答案 0 :(得分:0)
除了使用CoreData之外,这两个实现之间的主要区别在于“工作”版本是UIViewController
的子类:
class albumViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, MKMapViewDelegate { .... }
而抛出错误的版本是UICollectionViewController
的子类:
class albumViewController: coreDataCollectionViewController, MKMapViewDelegate { .... }
class coreDataCollectionViewController: UICollectionViewController { .... }
UICollectionViewControllers
要求他们的根view
是UICollectionView
或其子类。在你的故事板中,albumVC有一个collectionView,但不是根视图。
解决方案是将coreDataCollectionViewController
的类定义更改为子类UIViewController
并采用集合视图委托和数据源协议:
class albumViewController: coreDataCollectionViewController, MKMapViewDelegate { .... }
class coreDataCollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { .... }
另请注意,错误实际上是由mapViewController
场景抛出的,该场景也是coreDataCollectionViewController
的子类,并且在故事板中没有collectionView。上述修复也适用于此。