-5

I understand this question has been asked before and I have tried to understand the answers to apply to the code I am working with, for example both; Q1 & Q2

Previous Code with Error

let n = mutableRows.count
var i = 0, rows: [IndexPath] = []

for (i = 0; i < n; i += 1) {
  rows.append(mutableRows[i] as! IndexPath)
}

My Update to Swift 3.0

for i in stride(from: 0, to: n, by: +1){
  rows.append(mutableRows[i] as! IndexPath)
}

Even thought I don't get any errors the function does not work. Does anyone know how to correctly change the For statement to Swift 3.0 ?

Here's the full code;

func longPress(_ gesture: UILongPressGestureRecognizer) {
    let location = gesture.location(in: self)
    let indexPath = indexPathForRow(at: location)
    let sections = numberOfSections
    var rows = 0
    for i in 0 ..< sections {
        rows += numberOfRows(inSection: i)
    }

    // get out of here if the long press was not on a valid row or our table is empty
    // or the dataSource tableView:canMoveRowAtIndexPath: doesn't allow moving the row
    if (rows == 0 || (gesture.state == UIGestureRecognizerState.began && indexPath == nil) ||
        (gesture.state == UIGestureRecognizerState.ended && currentLocationIndexPath == nil)) {
            cancelGesture()
            return
    }

    // started
    if gesture.state == UIGestureRecognizerState.began {
        isEnabled = false
        let cell = cellForRow(at: indexPath!)!;
        //            draggingRowHeight = cell.frame.size.height;
        cell.setSelected(false, animated: false)
        cell.setHighlighted(false, animated: false)

        // make an image from the pressed tableview cell
        UIGraphicsBeginImageContextWithOptions(cell.bounds.size, false, 0)
        cell.layer.render(in: UIGraphicsGetCurrentContext()!)
        let cellImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        // create and image view that we will drag around the screen
        if draggingView == nil {
            draggingView = UIImageView(image: cellImage)
            addSubview(draggingView!)
            let rect = rectForRow(at: indexPath!)
            draggingView!.frame = draggingView!.bounds.offsetBy(dx: rect.origin.x, dy: rect.origin.y)

            // add drop shadow to image and lower opacity
            draggingView!.layer.masksToBounds = false
            draggingView!.layer.shadowColor = UIColor.black.cgColor
            draggingView!.layer.shadowOffset = CGSize(width: 0, height: 0);
            draggingView!.layer.shadowRadius = 4.0;
            draggingView!.layer.shadowOpacity = 0.7;
            draggingView!.layer.opacity = Float(draggingViewOpacity);

            // zoom image towards user
            UIView.beginAnimations("zoom", context: nil)
            draggingView!.transform = CGAffineTransform(scaleX: 1.1, y: 1.1);
            draggingView!.center = CGPoint(x: center.x, y: location.y);
            UIView.commitAnimations()
        }
        cell.isHidden = true;
        currentLocationIndexPath = indexPath;
        initialIndexPath = indexPath;

        // enable scrolling for cell
        scrollDisplayLink = CADisplayLink(target: self, selector: #selector(SBGestureTableView.scrollTableWithCell(_:)))
        scrollDisplayLink?.add(to: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
    }
        // dragging
    else if gesture.state == UIGestureRecognizerState.changed {
        var rect = bounds;
        // adjust rect for content inset as we will use it below for calculating scroll zones
        rect.size.height -= contentInset.top;
        let location = gesture.location(in: self);
        // tell us if we should scroll and which direction
        let scrollZoneHeight = rect.size.height / 6;
        let bottomScrollBeginning = contentOffset.y + contentInset.top + rect.size.height - scrollZoneHeight;
        let topScrollBeginning = contentOffset.y + contentInset.top  + scrollZoneHeight;
        // we're in the bottom zone
        if location.y >= bottomScrollBeginning {
            scrollRate = Double((location.y - bottomScrollBeginning) / scrollZoneHeight);
        }
            // we're in the top zone
        else if (location.y <= topScrollBeginning) {
            scrollRate = Double((location.y - topScrollBeginning) / scrollZoneHeight);
        }
        else {
            scrollRate = 0;
        }
    }
        // dropped
    else if gesture.state == UIGestureRecognizerState.ended {
        isEnabled = true
        let indexPath: IndexPath = currentLocationIndexPath!
        let cell = cellForRow(at: indexPath)!
        // remove scrolling CADisplayLink
        scrollDisplayLink?.invalidate();
        scrollDisplayLink = nil;
        scrollRate = 0;

        UIView.animate(withDuration: 0.3, animations: { () -> Void in
            let rect = self.rectForRow(at: indexPath)
            self.draggingView!.transform = CGAffineTransform.identity
            self.draggingView!.frame = self.draggingView!.bounds.offsetBy(dx: rect.origin.x, dy: rect.origin.y)
            }, completion: {(Bool) -> Void in
                self.draggingView!.removeFromSuperview()
                cell.isHidden = false
                let visibleRows: NSArray = self.indexPathsForVisibleRows! as NSArray
                let mutableRows = visibleRows.mutableCopy() as! NSMutableArray
                mutableRows.remove(indexPath)

                let n = mutableRows.count
                var i = 0, rows: [IndexPath] = []


                for (i = 0; i < n; i += 1) {
                   rows.append(mutableRows[i] as! IndexPath)
                }


                self.reloadRows(at: rows as [IndexPath], with: UITableViewRowAnimation.none)
                self.currentLocationIndexPath = nil
                self.draggingView = nil
        })
    }
}
Community
  • 1
  • 1
RileyDev
  • 2,950
  • 3
  • 26
  • 61
  • 3
    Why not simply `for row in mutableRows { rows.append(row) ...` (available since Swift 1.0) – vadian Sep 06 '16 at 18:59
  • PS: and why this ObjectiveC-ish `mutableCopy` and `NSMutableArray`?? Learn to use the benefit of Swift's native types, the difference of `let` and `var` and its strong type system. For example with `indexPathsForVisibleRows! as NSArray` you throw away the type information and have to re-cast it. That's pretty inefficient. – vadian Sep 06 '16 at 19:08
  • @vadian because row is actually type `int` and has no member `append` – RileyDev Sep 06 '16 at 19:22
  • No, at the mentioned moment `rows` is `[IndexPath]` -> see the line `var i = 0, rows: [IndexPath] = []` – vadian Sep 06 '16 at 19:39

2 Answers2

2

You can simply do this:

for row in mutableRows {
    rows.append(row as! IndexPath)
}

The for...in loop is very useful. In every iteration, the value of row is changed to the next item in the mutableRowsArray. And the loop ends when all items in the array has been iterated.

This is even simpler!

rows = mutableRows.map { $0 as! IndexPath }
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • I'm getting the error Value of type 'Int' has no member 'append' for `rows.append` this is because it isn't an array. `var rows = 0 for i in 0 ..< sections { rows += numberOfRows(inSection: i) }` – RileyDev Sep 06 '16 at 19:16
  • You're using `rows` twice (as `Int` and `[IndexPath]`). That's ambiguous and confusing. – vadian Sep 06 '16 at 19:20
  • Apparently you have two `rows` variables. It's very confusing if you can't tell already. Change the name of one of them. @JKSDEV – Sweeper Sep 06 '16 at 19:21
  • @Sweeper Yeah sorry, just re-read the code and fixed the naming and it works now. Thanks !! Sorry my boss is stressing me out about converting this to Swift 3 by tomorrow – RileyDev Sep 06 '16 at 19:27
2

You can directly append the array:

let visibleRows = (self.indexPathsForVisibleRows ?? [])
    .filter { $0 != indexPath }

rows.append(contentsOf: visibleRows)

There is no need to use NSMutableArray in Swift.

Sulthan
  • 128,090
  • 22
  • 218
  • 270