Swift: I want to know what is the index path row o

2019-09-10 22:26发布

问题:

I have a custom cell class given below:

class SizeAndQuantityCellView:UITableViewCell
{

@IBOutlet weak var imageview: UIImageView!
@IBOutlet weak var plusButton4x4: UIButton!
@IBOutlet weak var plusButton4x6: UIButton!
@IBOutlet weak var plusButton5x7: UIButton!
@IBOutlet weak var plusButton8x10: UIButton!
@IBOutlet weak var minusButton4x4: UIButton!
@IBOutlet weak var minusButton4x6: UIButton!
@IBOutlet weak var minusButton5x7: UIButton!
@IBOutlet weak var minusButton8x10: UIButton!
@IBOutlet weak var quantity4x4: UILabel!
@IBOutlet weak var quantity4x6: UILabel!
@IBOutlet weak var quantity5x7: UILabel!
@IBOutlet weak var quantity8x10: UILabel!

let sizeAndQuantityController = SizeAndQuantityController()
@IBAction func plusButtonClick(sender: UIButton)
{
    let btnTag:Int = sender.tag
    let tableView = sender.superview!.superview?.superview as! UITableView
    let cellRow = tableView.indexPathForCell(self)?.row
    sizeAndQuantityController.plusButtonClick(btnTag,cellRow: cellRow!)
}

@IBAction func minusButtonClick(sender: UIButton)
{
    let btnTag:Int = sender.tag
    let tableView = sender.superview!.superview?.superview as! UITableView
    let cellRow = tableView.indexPathForCell(self)?.row
    sizeAndQuantityController.plusButtonClick(btnTag,cellRow: cellRow!)
}
}

What i want to do is when i click the plus button the quantity should increase by one and when i click the minus button it should decrease by one. Here's my controller class for that:

class SizeAndQuantityController
{
func plusButtonClick(tag:Int,cellRow:Int)
{
    switch tag
    {
    case 13:
        let quant = quantity4x4[cellRow]
        quantity4x4[cellRow] = quant+1
        break;
    case 14:
        let quant = quantity4x6[cellRow]
        quantity4x6[cellRow] = quant+1
        break;
    case 15:
        let quant = quantity5x7[cellRow]
        quantity5x7[cellRow] = quant+1
        break;
    case 16:
        let quant = quantity8x10[cellRow]
        quantity8x10[cellRow] = quant+1
        break;
    default:
        break
    }
}

func minusButtonClick(tag:Int,cellRow:Int)
{
    switch tag
    {
    case 17:
        let quant = quantity4x4[cellRow]
        quantity4x4[cellRow] = quant-1
        break;
    case 18:
        let quant = quantity4x6[cellRow]
        quantity4x6[cellRow] = quant-1
        break;
    case 19:
        let quant = quantity5x7[cellRow]
        quantity5x7[cellRow] = quant-1
        break;
    case 20:
        let quant = quantity8x10[cellRow]
        quantity8x10[cellRow] = quant-1
        break;
    default:
        break
    }
}

i have given different tags to all the buttons. when i run the app it gives me the following error: "Could not cast value of type UITableViewWrapperView to UITableView" at the line where i set my tableview.

回答1:

Doing sender.superview!.superview?.superview as! UITableView is very dangerous. In the transition between iOS6 and iOS7, an extra layer was actually introduced and that kind of call failed.

Rather just have a property rowIndex in cell, which you set in your cellForRowAtIndexPath. For Example:

class SizeAndQuantityCellView:UITableViewCell
{
    var rowIndex: Int = 0
    ...
}

In your TableViewController

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let cell = tableView.dequeueReusableCell(withIdentifier: "myTableViewCell", for: indexPath) as! SizeAndQuantityCellView
   cell.rowIndex = indexPath.row
   ...
   return cell
}

From your code, it is not clear where quantity4x4[cellRow], for example, fits in but it seems to me that a Delegation Pattern might also be handy. I.o.w. Create a delegate protocol for SizeAndQuantityCellView and let your ViewController be the delegate of SizeAndQuantityCellView. When the buttons is tapped, fire an event to the delegate. That way your ViewController can handle the logic upon the pressing of the buttons.



回答2:

A more sofisticated approach, involves the use of extensions and bitwise operator. Simplifying, you can use the tag property built-in with every UIButton, to store the whole value of of and IndexPath (that is identified by a row and a section) by packing it using bitwise operators and shifting.

Once the value is stored, you can use the computed property technique by extending your UIButton class and returning a new IndexPath that is created by unpacking the original values.

Below there's a simple extension that do the job:

extension UIButton {
    func packing(low:Int, high:Int) -> Int {
        //With the packing function we force our Packed number to be a 64 bit one
        //we shift the high part 32bits to the left and OR the resulting value with the low part
        return ((high << 32) | low)
    }
    func unpackHigh(packed:Int) -> Int {
        //Unpacking the high part involve swifting to right the 
        //number in order to zero'ing all the non relevant bits.
        return packed >> 32
    }
    func unpackLow(packed:Int) -> Int {
        //Unpacking the low part involve masking the whole packed number with the max value allowed for an Int.
        //note that using the Int.max function does not work as expected, returning a compile error. 
        //Maybe, it's a bug of compiler.
        let mask = 2147483647
        return mask & packed
    }

    //since we cannot use stored property on extensions, we need to compute realtime, every time the
    //right value of our indexPath.
    var indexPath:IndexPath {
        get {
            return IndexPath(row: unpackLow(packed: self.tag), section: unpackHigh(packed: self.tag))
        }
        set {
            self.tag = packing(low: newValue.row, high: newValue.section)
        }
    }
}

and here you can find a simple application on a prototype cellForRowAtIndexPath:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let aCell = tableView.dequeueReusableCell(withIdentifier: "reuseCell") as! CustomTableViewCell

...

aCell.aButton.indexPath = indexPath

...

return aCell

}

note that you need to pass, after the dequeue, the right indexPath to the cell, in order to trigger the extension methods.



标签: ios swift xcode