Ios UICollectionViewCell消息在退出队列后立即发送到解除分配的实例
我有一个UICollectionViewCell,它正在排队等待重用。我最近引入了一个滑动抽屉功能,它基本上是一个隐藏视图,当用户滑动时会显示出来 在上次更改之后,这似乎创建了一个实例在初始化时被释放的情况。报告僵尸的确切位置是在调用“addGestureRecognizers()”时,从setupSlidingDrawer()调用“addGestureRecognizers()”,而setupSlidingDrawer()又从init函数调用 我附上了一张僵尸呼叫前后断点的图片。我整天都在看这个,一直在画空白 作为一种变通方法(hack),我将deleteView作为一个实例变量,这似乎可以防止类释放,因为保留计数没有减少 我觉得我的集合视图单元格/控制器的代码非常标准,我没有做任何疯狂的事情 这似乎是一个苹果的错误,但我似乎无法在互联网上找到任何东西来证明这一点。如果Ios UICollectionViewCell消息在退出队列后立即发送到解除分配的实例,ios,iphone,swift,swift2,Ios,Iphone,Swift,Swift2,我有一个UICollectionViewCell,它正在排队等待重用。我最近引入了一个滑动抽屉功能,它基本上是一个隐藏视图,当用户滑动时会显示出来 在上次更改之后,这似乎创建了一个实例在初始化时被释放的情况。报告僵尸的确切位置是在调用“addGestureRecognizers()”时,从setupSlidingDrawer()调用“addGestureRecognizers()”,而setupSlidingDrawer()又从init函数调用 我附上了一张僵尸呼叫前后断点的图片。我整天都在看这
class MomentsViewCell : UICollectionViewCell, UIGestureRecognizerDelegate {
static let reuseIdentifier = "MomentsViewCell"
let imageView = UIImageView()
let activityIndicator = UIActivityIndicatorView()
let shareButton = UIButton()
var shareCallback: (() -> ())?
var isSwiped = false
let overlayViewTag = 999
var delegate: MomentsViewController?
let shareButtonLength: CGFloat = 44
lazy var drawerWidth: CGFloat = {
self.frame.width * 0.15
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(imageView)
imageView.contentMode = UIViewContentMode.ScaleAspectFit
imageView.snp_makeConstraints { (make) -> Void in
make.centerX.equalTo(self.contentView.snp_centerX)
make.width.equalTo(self.contentView.snp_width)
make.top.equalTo(self.snp_top)
make.bottom.equalTo(self.snp_bottom)
}
contentView.addSubview(activityIndicator)
activityIndicator.hidesWhenStopped = true
activityIndicator.snp_makeConstraints { (make) -> Void in
make.center.equalTo(self.snp_center)
}
let shareImage = UIImage(named: "share-moment")
shareButton.setImage(shareImage, forState: .Normal)
shareButton.addTarget(self, action: "didTapShareButton", forControlEvents: .TouchUpInside)
shareButton.enabled = false
shareButton.alpha = 0.0
imageView.addSubview(shareButton)
imageView.userInteractionEnabled = true
shareButton.snp_makeConstraints { (make) -> Void in
let size = CGSizeMake(shareButtonLength, shareButtonLength)
var offset = shareButtonLength / 2
if let imageLength = shareImage?.size.height {
offset = (shareButtonLength - imageLength) / 2
}
make.bottom.equalTo(self.imageView).multipliedBy(0.95).offset(offset)
make.right.equalTo(self.imageView).multipliedBy(0.95).offset(offset)
make.size.equalTo(size)
}
setupSlidingDrawer()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
exitDeleteMode()
}
func enableSharing() {
shareButton.enabled = true
shareButton.alpha = 1.0
}
func didTapShareButton() {
shareCallback?()
}
func setupSlidingDrawer() {
let deleteView = UIView(frame: CGRectMake(self.frame.width - drawerWidth, self.frame.origin.y, drawerWidth, self.frame.height))
deleteView.backgroundColor = UIColor.whiteColor()
let deleteGradientLayer = CAGradientLayer()
deleteGradientLayer.frame = deleteView.bounds
deleteGradientLayer.colors = [UIColor(hex: 0xE8557C).CGColor, UIColor(hex: 0xCC2B49).CGColor]
deleteView.layer.insertSublayer(deleteGradientLayer, atIndex: 0)
let trashButton = UIButton()
trashButton.setImage(UIImage(named: "trash_can"), forState: UIControlState.Normal)
trashButton.addTarget(self, action: Selector("didPressDelete"), forControlEvents: .TouchUpInside)
deleteView.addSubview(trashButton)
deleteView.bringSubviewToFront(trashButton)
trashButton.snp_makeConstraints(closure: { (make) -> Void in
make.center.equalTo(deleteView.snp_center)
make.width.equalTo(deleteView.snp_width).multipliedBy(0.354)
make.height.equalTo(deleteView.snp_height).multipliedBy(0.07)
})
contentView.addSubview(deleteView)
deleteView.snp_makeConstraints(closure: { (make) -> Void in
make.left.equalTo(self.imageView.snp_right)
make.height.equalTo(self.contentView.snp_height)
make.width.equalTo(drawerWidth)
})
addGestureRecognizers()
}
func addGestureRecognizers() {
let swipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("didSwipeCell:"))
swipeGestureRecognizer.delegate = self
swipeGestureRecognizer.direction = .Left
self.addGestureRecognizer(swipeGestureRecognizer)
}
class MomentsViewController: ContainerSubController, UICollectionViewDelegate, UICollectionViewDataSource {
var moments: [Moment] = []
let layout = UICollectionViewFlowLayout()
var collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: UICollectionViewFlowLayout())
let headerIdentifier = "headerCellIdentifier"
let headerLabelText = "Moments"
let headerCellHeight: CGFloat = 103.0
let noMomentsLabelText = "It's looking pretty empty in here! Assign a Moments action (Share Moment To Twitter) to a Hot Key to get started."
let noMomentsReuseIdentifier = "NoMoments"
var currentSwipedCellIndexPath: NSIndexPath?
override func viewDidLoad() {
super.viewDidLoad()
layout.minimumLineSpacing = 0
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout)
collectionView.showsVerticalScrollIndicator = false
collectionView.backgroundColor = UIColor.clearColor()
collectionView.registerClass(MomentsViewCell.self, forCellWithReuseIdentifier: MomentsViewCell.reuseIdentifier)
collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: noMomentsReuseIdentifier)
collectionView.registerClass(UICollectionViewCell.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)
collectionView.delegate = self
collectionView.dataSource = self
view.backgroundColor = UIColor.blackColor()
view.addSubview(collectionView)
collectionView.snp_makeConstraints { (make) -> Void in
make.height.equalTo(view)
make.width.equalTo(view)
make.center.equalTo(view)
}
setupTransitionToMainButton()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
refreshMoments()
collectionView.reloadData()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleMomentSavedNotifcation", name: MomentNotifcation.MomentSaved.rawValue, object: nil)
}
//MARK: UICollectionViewDataSource
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
guard let momentsViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(MomentsViewCell.reuseIdentifier, forIndexPath: indexPath) as? MomentsViewCell, moment = moments[safe:indexPath.row] else {
return MomentsViewCell()
}
在你的守卫中,确保返回你之前排队的
momentsViewCell
例如:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if let momentsViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(MomentsViewCell.reuseIdentifier, forIndexPath: indexPath) as? MomentsViewCell {
return momentsViewCell
else {
return MomentsViewCell()
}
编辑
正如我看到的屏幕截图,日志是关于优化的警告。整个赋值可能不起作用,因为后来没有使用变量。这是我们尝试的第一件事情之一,因为我们认为它们没有引用单元格,这就是导致其释放的原因,但它不起作用。当collectionView.dequeueReusableCellWithReuseIdentifier->init()时,将发生释放。因此,它是在变量初始化之前发布的。您能否详细说明(并在编辑问题时从问题中删除无用的图像)您到底做了什么以及结果是什么?此外,子视图不
弱
也是很少见的。我不确定,现在是否可以,或者可能相关。我们移除了保护并直接使用:if let momentsViewCell=collectionView.dequeueReusableCellWithReuseIdentifier(momentsViewCell.reuseIdentifier,forIndexPath:indexPath)分配了矩单元作为?MomentsViewCell{对于弱子视图,我们没有使用outlet,因此不需要它们。尽管现在您在一个完全不相关的注释中提到了它,委托变量应该是弱的,