Swift - 集合视图 dequeueReusableCellWithReuseIdentifier EXC 错误访问错误
Swift - Collection View dequeueReusableCellWithReuseIdentifier EXC Bad Access Error
我正在开发一个有 UICollectionView
的应用程序。我创建了一个包含 UIImageView
和 UILabel
的自定义集合视图单元格。
以下代码导致 EXC_BAD_ACCESS (code=1, address=0x0) error on UICollectionView.dequeueReusableCellWithReuseIdentifier
in cellForItemAtIndexPath
方法。
这是我的代码:
import UIKit
class CategoryCell : UICollectionViewCell {
@IBOutlet var categoryImageView : UIImageView?
@IBOutlet var categoryLabel : UILabel?
}
class CatalogCollectionViewController: UIViewController, UICollectionViewDelegate , UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
@IBOutlet var categoriesCollectionView : UICollectionView?
var screenSize : CGRect?
override func viewDidLoad() {
super.viewDidLoad()
screenSize = UIScreen.mainScreen().bounds
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: screenSize!.width/2-30 , height: screenSize!.width/2-30 )
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
self.categoriesCollectionView?.delegate = self
self.categoriesCollectionView?.dataSource = self
categoriesCollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
self.categoriesCollectionView?.registerClass(CategoryCell.self, forCellWithReuseIdentifier: "CategoryCell")
self.categoriesCollectionView?.backgroundColor=UIColor.whiteColor()
self.view.addSubview(categoriesCollectionView!)
}
override func viewWillAppear(animated: Bool) {
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = categoriesCollectionView!.dequeueReusableCellWithReuseIdentifier("CategoryCell", forIndexPath: indexPath) as! CategoryCell
cell.layer.borderWidth = 2.0
cell.layer.borderColor = UIColor.grayColor().CGColor
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(self.view.frame.size.width/2-30, self.view.frame.size.width/2-30)
}
}
po 电池输出(调试器):
error: Execution was interrupted, reason: EXC_BAD_ACCESS
(code=1,address=0x0).
The process has been returned to the state before expression evaluation.
完整的堆栈跟踪:
* thread #1: tid = 0xdbea, 0x280abd6a UIKit`-[UICollectionViewData layoutAttributesForItemAtIndexPath:] + 274, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
frame #0: 0x280abd6a UIKit`-[UICollectionViewData layoutAttributesForItemAtIndexPath:] + 274
frame #1: 0x28825da4 UIKit`-[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:] + 312
frame #2: 0x280abc38 UIKit`-[UICollectionView dequeueReusableCellWithReuseIdentifier:forIndexPath:] + 164
* frame #3: 0x0010d428 SwiftTest`SwiftTest.CatalogCollectionViewController.collectionView (collectionView=0x1725c200, indexPath=0x16d9c560, self=0x16dbd260)(__ObjC.UICollectionView, cellForItemAtIndexPath : __ObjC.NSIndexPath) -> __ObjC.UICollectionViewCell + 296 at CatalogCollectionViewController.swift:50
frame #4: 0x0010d850 SwiftTest`@objc SwiftTest.CatalogCollectionViewController.collectionView (SwiftTest.CatalogCollectionViewController)(__ObjC.UICollectionView, cellForItemAtIndexPath : __ObjC.NSIndexPath) -> __ObjC.UICollectionViewCell + 92 at CatalogCollectionViewController.swift:0
frame #5: 0x2881fa74 UIKit`-[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:] + 408
frame #6: 0x280abb82 UIKit`-[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:] + 30
frame #7: 0x280a9c6e UIKit`-[UICollectionView _updateVisibleCellsNow:] + 3726
frame #8: 0x280a50aa UIKit`-[UICollectionView layoutSubviews] + 226
frame #9: 0x28041a82 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 714
frame #10: 0x2611dad4 QuartzCore`-[CALayer layoutSublayers] + 128
frame #11: 0x261191d0 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 352
frame #12: 0x28057f9a UIKit`-[UIView(Hierarchy) layoutBelowIfNeeded] + 962
frame #13: 0x28103aac UIKit`-[UINavigationController _layoutViewController:] + 1168
frame #14: 0x2810173e UIKit`-[UINavigationController _layoutTopViewController] + 250
frame #15: 0x2811a55e UIKit`-[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] + 634
frame #16: 0x2811a2ba UIKit`-[UINavigationTransitionView _notifyDelegateTransitionDidStopWithContext:] + 370
frame #17: 0x2811a006 UIKit`-[UINavigationTransitionView _cleanupTransition] + 758
frame #18: 0x280806b8 UIKit`-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 204
frame #19: 0x2807e9ec UIKit`+[UIViewAnimationState popAnimationState] + 324
frame #20: 0x2810d060 UIKit`-[UINavigationTransitionView transition:fromView:toView:] + 1732
frame #21: 0x2810c996 UIKit`-[UINavigationTransitionView transition:toView:] + 26
frame #22: 0x28103278 UIKit`-[UINavigationController _startTransition:fromViewController:toViewController:] + 2548
frame #23: 0x2810251a UIKit`-[UINavigationController _startDeferredTransitionIfNeeded:] + 834
frame #24: 0x2810216c UIKit`-[UINavigationController __viewWillLayoutSubviews] + 52
frame #25: 0x281020e6 UIKit`-[UILayoutContainerView layoutSubviews] + 214
frame #26: 0x28041a82 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 714
frame #27: 0x2611dad4 QuartzCore`-[CALayer layoutSublayers] + 128
frame #28: 0x261191d0 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 352
frame #29: 0x26119060 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16
frame #30: 0x26118580 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 368
frame #31: 0x26118232 QuartzCore`CA::Transaction::commit() + 614
frame #32: 0x261119ee QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 138
frame #33: 0x23e70b20 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 20
frame #34: 0x23e6ee16 CoreFoundation`__CFRunLoopDoObservers + 282
frame #35: 0x23e6f254 CoreFoundation`__CFRunLoopRun + 972
frame #36: 0x23dc1bb8 CoreFoundation`CFRunLoopRunSpecific + 516
frame #37: 0x23dc19ac CoreFoundation`CFRunLoopRunInMode + 108
frame #38: 0x2503baf8 GraphicsServices`GSEventRunModal + 160
frame #39: 0x280adfb4 UIKit`UIApplicationMain + 144
frame #40: 0x00108050 SwiftTest`main + 164 at AppDelegate.swift:12
这样做比较好,
if let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CategoryCell", forIndexPath: indexPath) as? CategoryCell { .....(rest of your method code) }
通过这种方式,您可以确保在尝试 运行 代码之前确实拥有一个可重复使用的单元格。另外,最好使用方法 collectionView 而不是任何插座。
我从您的评论和 @IBOutlet
参考中推断您有一个包含集合视图和原型单元格的场景。如果是这种情况,您不应该以编程方式实例化另一个集合视图(故事板将为您实例化一个)。同样,如果您的原型单元具有适当的故事板 ID("collection view reusable cell" 的 "identifier")和基数 class(因为,否则,您不能使用单元格 @IBOutlet
引用)。
很难判断崩溃是您以编程方式创建的集合视图还是情节提要中的集合视图的结果。例如,您以编程方式将 delegate
和 dataSource
设置为故事板创建的集合视图,然后创建了另一个从未设置这些委托的集合视图)。问题也可能源于故事板的集合视图调用了您的委托方法来创建单元格,但是因为您引用了您的集合视图出口(现在正在引用另一个集合视图)而不是 collectionView
被通过了,它无法处理那个。
但是,如果您只是消除程序化集合视图并坚持使用情节提要中的视图,生活就会容易得多。
当我执行以下操作时,效果很好:
class CategoryCell : UICollectionViewCell {
@IBOutlet var categoryImageView : UIImageView?
@IBOutlet var categoryLabel : UILabel?
}
class CatalogCollectionViewController: UIViewController {
@IBOutlet weak var categoriesCollectionView : UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
let screenSize = UIScreen.mainScreen().bounds
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: screenSize.width/2-30 , height: screenSize.width/2-30 )
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
categoriesCollectionView!.collectionViewLayout = layout
categoriesCollectionView!.backgroundColor=UIColor.whiteColor()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated) // if you override these methods, call `super`
// presumably you're doing something else here; if not, remove this whole method
}
}
// If you want, you can define conformance of these protocols in separate extensions, to
// keep it perfectly clear which methods are for which protocol. If you'd rather keep this
// all in the base class definition, you can, though.
extension CatalogCollectionViewController : UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
// I'd suggest using `collectionView` parameter in `cellForItemAtIndexPath`
// rather than referencing some other outlet
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CategoryCell", forIndexPath: indexPath) as! CategoryCell
cell.layer.borderWidth = 2.0
cell.layer.borderColor = UIColor.grayColor().CGColor
cell.categoryImageView!.image = UIImage(named: "test")
cell.categoryLabel!.text = "foo"
return cell
}
}
extension CatalogCollectionViewController : UICollectionViewDelegateFlowLayout {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(self.view.frame.size.width/2-30, self.view.frame.size.width/2-30)
}
}
注意,我在 Interface Builder 中设置了集合视图的 delegate
和 dataSource
(因此我不需要在上面以编程方式进行)。但如果你愿意,你也可以通过编程方式设置这些。但是不要实例化另一个集合视图。故事板已经为您创建了一个。
我正在开发一个有 UICollectionView
的应用程序。我创建了一个包含 UIImageView
和 UILabel
的自定义集合视图单元格。
以下代码导致 EXC_BAD_ACCESS (code=1, address=0x0) error on UICollectionView.dequeueReusableCellWithReuseIdentifier
in cellForItemAtIndexPath
方法。
这是我的代码:
import UIKit
class CategoryCell : UICollectionViewCell {
@IBOutlet var categoryImageView : UIImageView?
@IBOutlet var categoryLabel : UILabel?
}
class CatalogCollectionViewController: UIViewController, UICollectionViewDelegate , UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
@IBOutlet var categoriesCollectionView : UICollectionView?
var screenSize : CGRect?
override func viewDidLoad() {
super.viewDidLoad()
screenSize = UIScreen.mainScreen().bounds
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: screenSize!.width/2-30 , height: screenSize!.width/2-30 )
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
self.categoriesCollectionView?.delegate = self
self.categoriesCollectionView?.dataSource = self
categoriesCollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
self.categoriesCollectionView?.registerClass(CategoryCell.self, forCellWithReuseIdentifier: "CategoryCell")
self.categoriesCollectionView?.backgroundColor=UIColor.whiteColor()
self.view.addSubview(categoriesCollectionView!)
}
override func viewWillAppear(animated: Bool) {
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = categoriesCollectionView!.dequeueReusableCellWithReuseIdentifier("CategoryCell", forIndexPath: indexPath) as! CategoryCell
cell.layer.borderWidth = 2.0
cell.layer.borderColor = UIColor.grayColor().CGColor
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(self.view.frame.size.width/2-30, self.view.frame.size.width/2-30)
}
}
po 电池输出(调试器):
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1,address=0x0). The process has been returned to the state before expression evaluation.
完整的堆栈跟踪:
* thread #1: tid = 0xdbea, 0x280abd6a UIKit`-[UICollectionViewData layoutAttributesForItemAtIndexPath:] + 274, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
frame #0: 0x280abd6a UIKit`-[UICollectionViewData layoutAttributesForItemAtIndexPath:] + 274
frame #1: 0x28825da4 UIKit`-[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:] + 312
frame #2: 0x280abc38 UIKit`-[UICollectionView dequeueReusableCellWithReuseIdentifier:forIndexPath:] + 164
* frame #3: 0x0010d428 SwiftTest`SwiftTest.CatalogCollectionViewController.collectionView (collectionView=0x1725c200, indexPath=0x16d9c560, self=0x16dbd260)(__ObjC.UICollectionView, cellForItemAtIndexPath : __ObjC.NSIndexPath) -> __ObjC.UICollectionViewCell + 296 at CatalogCollectionViewController.swift:50
frame #4: 0x0010d850 SwiftTest`@objc SwiftTest.CatalogCollectionViewController.collectionView (SwiftTest.CatalogCollectionViewController)(__ObjC.UICollectionView, cellForItemAtIndexPath : __ObjC.NSIndexPath) -> __ObjC.UICollectionViewCell + 92 at CatalogCollectionViewController.swift:0
frame #5: 0x2881fa74 UIKit`-[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:] + 408
frame #6: 0x280abb82 UIKit`-[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:] + 30
frame #7: 0x280a9c6e UIKit`-[UICollectionView _updateVisibleCellsNow:] + 3726
frame #8: 0x280a50aa UIKit`-[UICollectionView layoutSubviews] + 226
frame #9: 0x28041a82 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 714
frame #10: 0x2611dad4 QuartzCore`-[CALayer layoutSublayers] + 128
frame #11: 0x261191d0 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 352
frame #12: 0x28057f9a UIKit`-[UIView(Hierarchy) layoutBelowIfNeeded] + 962
frame #13: 0x28103aac UIKit`-[UINavigationController _layoutViewController:] + 1168
frame #14: 0x2810173e UIKit`-[UINavigationController _layoutTopViewController] + 250
frame #15: 0x2811a55e UIKit`-[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] + 634
frame #16: 0x2811a2ba UIKit`-[UINavigationTransitionView _notifyDelegateTransitionDidStopWithContext:] + 370
frame #17: 0x2811a006 UIKit`-[UINavigationTransitionView _cleanupTransition] + 758
frame #18: 0x280806b8 UIKit`-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 204
frame #19: 0x2807e9ec UIKit`+[UIViewAnimationState popAnimationState] + 324
frame #20: 0x2810d060 UIKit`-[UINavigationTransitionView transition:fromView:toView:] + 1732
frame #21: 0x2810c996 UIKit`-[UINavigationTransitionView transition:toView:] + 26
frame #22: 0x28103278 UIKit`-[UINavigationController _startTransition:fromViewController:toViewController:] + 2548
frame #23: 0x2810251a UIKit`-[UINavigationController _startDeferredTransitionIfNeeded:] + 834
frame #24: 0x2810216c UIKit`-[UINavigationController __viewWillLayoutSubviews] + 52
frame #25: 0x281020e6 UIKit`-[UILayoutContainerView layoutSubviews] + 214
frame #26: 0x28041a82 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 714
frame #27: 0x2611dad4 QuartzCore`-[CALayer layoutSublayers] + 128
frame #28: 0x261191d0 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 352
frame #29: 0x26119060 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16
frame #30: 0x26118580 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 368
frame #31: 0x26118232 QuartzCore`CA::Transaction::commit() + 614
frame #32: 0x261119ee QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 138
frame #33: 0x23e70b20 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 20
frame #34: 0x23e6ee16 CoreFoundation`__CFRunLoopDoObservers + 282
frame #35: 0x23e6f254 CoreFoundation`__CFRunLoopRun + 972
frame #36: 0x23dc1bb8 CoreFoundation`CFRunLoopRunSpecific + 516
frame #37: 0x23dc19ac CoreFoundation`CFRunLoopRunInMode + 108
frame #38: 0x2503baf8 GraphicsServices`GSEventRunModal + 160
frame #39: 0x280adfb4 UIKit`UIApplicationMain + 144
frame #40: 0x00108050 SwiftTest`main + 164 at AppDelegate.swift:12
这样做比较好,
if let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CategoryCell", forIndexPath: indexPath) as? CategoryCell { .....(rest of your method code) }
通过这种方式,您可以确保在尝试 运行 代码之前确实拥有一个可重复使用的单元格。另外,最好使用方法 collectionView 而不是任何插座。
我从您的评论和 @IBOutlet
参考中推断您有一个包含集合视图和原型单元格的场景。如果是这种情况,您不应该以编程方式实例化另一个集合视图(故事板将为您实例化一个)。同样,如果您的原型单元具有适当的故事板 ID("collection view reusable cell" 的 "identifier")和基数 class(因为,否则,您不能使用单元格 @IBOutlet
引用)。
很难判断崩溃是您以编程方式创建的集合视图还是情节提要中的集合视图的结果。例如,您以编程方式将 delegate
和 dataSource
设置为故事板创建的集合视图,然后创建了另一个从未设置这些委托的集合视图)。问题也可能源于故事板的集合视图调用了您的委托方法来创建单元格,但是因为您引用了您的集合视图出口(现在正在引用另一个集合视图)而不是 collectionView
被通过了,它无法处理那个。
但是,如果您只是消除程序化集合视图并坚持使用情节提要中的视图,生活就会容易得多。
当我执行以下操作时,效果很好:
class CategoryCell : UICollectionViewCell {
@IBOutlet var categoryImageView : UIImageView?
@IBOutlet var categoryLabel : UILabel?
}
class CatalogCollectionViewController: UIViewController {
@IBOutlet weak var categoriesCollectionView : UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
let screenSize = UIScreen.mainScreen().bounds
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: screenSize.width/2-30 , height: screenSize.width/2-30 )
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
categoriesCollectionView!.collectionViewLayout = layout
categoriesCollectionView!.backgroundColor=UIColor.whiteColor()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated) // if you override these methods, call `super`
// presumably you're doing something else here; if not, remove this whole method
}
}
// If you want, you can define conformance of these protocols in separate extensions, to
// keep it perfectly clear which methods are for which protocol. If you'd rather keep this
// all in the base class definition, you can, though.
extension CatalogCollectionViewController : UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
// I'd suggest using `collectionView` parameter in `cellForItemAtIndexPath`
// rather than referencing some other outlet
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CategoryCell", forIndexPath: indexPath) as! CategoryCell
cell.layer.borderWidth = 2.0
cell.layer.borderColor = UIColor.grayColor().CGColor
cell.categoryImageView!.image = UIImage(named: "test")
cell.categoryLabel!.text = "foo"
return cell
}
}
extension CatalogCollectionViewController : UICollectionViewDelegateFlowLayout {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(self.view.frame.size.width/2-30, self.view.frame.size.width/2-30)
}
}
注意,我在 Interface Builder 中设置了集合视图的 delegate
和 dataSource
(因此我不需要在上面以编程方式进行)。但如果你愿意,你也可以通过编程方式设置这些。但是不要实例化另一个集合视图。故事板已经为您创建了一个。