UICollectionViewCell消息在出列后立即发送到解除分配的实例

时间:2016-01-29 03:17:47

标签: ios iphone swift swift2

我有一个UICollectionViewCell,它正在出列以供重用。我最近推出了一个滑动抽屉功能,它基本上是一个隐藏视图,当用户滑动时会显示该视图。

在最后一次更改之后,这似乎创建了一个实例在初始化时被释放的情况。报告Zombie的确切位置是在" addGestureRecognizers()"从setupSlidingDrawer()调用,然后从init函数调用它。

我在Zombie电话之前和之后附上了断点的图像。我一整天都在拉着头发看着这个并继续画一个空白。

作为一种解决方法(hack)我已经使deleteView成为一个实例变量,这似乎使得类不会被释放,因为保留计数不会减少。

我觉得我的收藏视图单元/控制器的代码非常标准,我没有做任何疯狂的事情。

这似乎是一个苹果虫,但我似乎无法在网络上找到任何东西来证明它。如果

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()
        }

enter image description here

1 个答案:

答案 0 :(得分:0)

在警卫中,请务必返回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()
   }

修改

在我看到屏幕截图时,日志会警告优化。整个赋值可能不起作用,因为稍后不会使用该变量。