Swift:通过引用传递修改UIButtons数组

时间:2019-01-22 12:29:40

标签: arrays swift uiview

问题:无法通过inout参数传递不可变值:“ cardView”是“ let”常量

我找到的解决方案1(但有不良行为): 当我只是跳过inout声明和“&”时,代码可以正常工作。但是视图不会立即更新。

// Line 3: updateCardView(...) is producing the error   
private func updateViewFromModel() {
        ...
        for (index, cardView) in cardsContainerView.cardViews.enumerated() {
            updateCardView(game.handedOutCards[index], &cardView)       
        }
  }

   private func updateCardView (_ card: Card, _ cardView: inout CardView)  {
       cardView.layerState(cardView: &cardView)
       cardView.layer.borderColor = #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1).cgColor
  }


class CardsContainerView: UIView {
    var cardViews = [CardView](){
    didSet {
        setNeedsLayout()
    }
}

class CardView: UIButton {
     func layerState(cardView: inout CardView) {
         cardView.layer.cornerRadius = 3
         cardView.layer.borderWidth = 2 
     }
 }

解决方案2有效,但仅当layerState()为空时:

private func updateViewFromModel() {
     ...
     for index in cardsContainerView.cardViews.indices {
         updateCardView(game.handedOutCards[index], cardsContainerView.cardViews[index])       
     }
}

private func updateCardView (_ card: Card, _ cardView: CardView)  {
    cardView.layer.borderWidth = 2
    cardView.layerState()
    cardView.layer.borderColor = #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1).cgColor
}


class CardsContainerView: UIView {
    var cardViews = [CardView](){
    didSet {
        setNeedsLayout()
    }
}

class CardView: UIButton {
     func layerState() {
         // Setting a border within this function is not working as expected
         // The borders of the cards are only shown after another touch event and only for old objects of cardViews
         //self.layer.borderWidth = 2
     }
 }

预期结果: 每个新按钮在创建和更新视图后应立即显示一个边框。边框参数应在layerState()内设置。

实际结果:layerState()内设置borderWidth时,不会立即显示边框。但是,在另一次触摸事件之后,cardView的现有实例具有预期的边框。

1 个答案:

答案 0 :(得分:3)

cardView是一个let常量,因为它是由for循环创建的。您可以通过添加var关键字使其成为var

for (index, var cardView) in cardsContainerView.cardViews.enumerated() {
    updateCardView(game.handedOutCards[index], &cardView)       
}

但这有点混乱,因为您仍在创建一个新变量,该变量引用数组中的变量,然后传递该变量。之所以有效,是因为数组中的变量和新变量都是对卡片对象的引用,但是整个inout都是浪费的,因为您只是在{循环。

您可以将循环更改为:

cardView

在这里,您正在使用for index in cardsContainerView.cardViews.indices { updateCardView(game.handedOutCards[index], &cardsContainerView.cardViews[index]) } 从数组中查找并直接传递值,因此将更新数组项。如果indexcardView而不是struct,这甚至可以工作。

但是,由于您正在使用class,因此可以在不使用class的情况下更新对象。


您应该使用inout来更新对象,而不要使用self来传递引用:

inout