2016-01-29 48 views
0

我有一個UICollectionViewCell,它正在出列以供重用。我最近引入了一個滑動抽屜功能,它基本上是一個隱藏的視圖,當用戶滑動時顯示。UICollectionViewCell消息在出列後立即發送到解除分配的實例

在最後一次更改後,這似乎創建了一個實例正在被初始化時釋放的情況。殭屍被報告的確切位置是在調用「addGestureRecognizers()」時從setupSlidingDrawer()調用的,然後由init函數調用它。

我在殭屍呼叫之前和之後附加了一個斷點圖像。我一整天都在拉着我的頭髮看着這個,並不斷畫空白。

作爲一個解決辦法(黑客)我已經使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

回答

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

編輯

當我看到截圖,日誌警告關於優化。整個分配可能無法正常工作,因爲稍後不會使用該變量。

+0

這是我們嘗試的第一件事情之一,因爲我們認爲他們沒有提及細胞,這是什麼導致其釋放,但它沒有奏效。 該版本發生在collectionView.dequeueReusableCellWithReuseIdentifier - > init()時。所以它在變量被初始化之前被釋放。 – Constantine

+0

您可以詳細說明(並在編輯時從您的問題中刪除不實用的圖片)您做了什麼以及結果是什麼?此外,讓子視圖不「弱」是非常不尋常的。我不確定,如果那沒關係,或者可能相關。 – SmokeDispenser

+0

我們刪除了警衛,並直接使用分配的瞬間單元格: 如果讓momentsViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(MomentsViewCell.reuseIdentifier,forIndexPath:indexPath)爲? MomentsViewCell { } 同樣就弱子視圖而言,我們不使用插座,所以它們不是必需的。儘管現在你在一個完全不相關的說明中提到它,但代表var應該很弱, – Constantine

相關問題