프로그래밍/iOS

[UIKit] TableViewCell에서 AutoLayout 동적으로 추가 및 삭제하기(AutoLayout programmatically Swift)

병인 2022. 12. 25. 14:11

프로젝트를 하던 도중 TableViewCell에 AutoLayout을 동적으로 추가를 할 일이 생겼다.

 

하단은 프로필에 상태메세지가 없을 경우 사용자 이름을 centerYAnchor로 주는 코드이다.

if(self.dataSource[indexPath.section][indexPath.row].statusMsg == nil) {
	cell.name.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
} else {
	cell.name.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
	cell.statusMessage.text = self.dataSource[indexPath.section][indexPath.row].statusMsg
}

 

여기서 TableViewCell의 Reuse 부분에서 문제가 생겼다.

 

나는 당연히 isActive = true / false 하면 해당 제약조건이 없어질 줄 알았으나... 하단의 이미지를 보고 맨탈이 붕괴되었다.

 

우선 기초적인 Reuse하면서 초기화 하는 부분을 빼먹었다. 

override func prepareForReuse() {
    image.image = nil
    name.text = nil
    statusMessage.text = nil
}

 

하지만 제약 조건은 돌아오지 않았다.

해당 부분에 대해 검색을 해보니 하단의 코드는 새로운 제약조건을 추가하고 Active만 false 처리 되는 코드인 것이다.

if(self.dataSource[indexPath.section][indexPath.row].statusMsg == nil) {
	cell.name.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
} else {
	cell.name.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
	cell.statusMessage.text = self.dataSource[indexPath.section][indexPath.row].statusMsg
}

 

따라서 programmatically 하게 한답시고 Cell을 재사용 할 때마다 신규 제약 조건을 매우 많이 추가해주고 있는 것이다.

 

이 부분을 해결하기 위해 Cell에 제약조건을 변수로 두고 해당 변수의 active를 활성 / 비활성화 해주어 해결했다.

 

class tableViewCell : UITableViewCell {

  var nameCenterYAnchorConstraint : NSLayoutConstraint?
	
  override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    nameCenterYAnchorConstraint = name.centerYAnchor.constraint(equalTo: self.centerYAnchor)
    setLayout()
  }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCell.identifier, for: indexPath) as! tableViewCell
	
  if(self.dataSource[indexPath.section][indexPath.row].statusMsg == nil) {
    cell.nameCenterYAnchorConstraint?.isActive = true
  } else {
    cell.nameCenterYAnchorConstraint?.isActive = false
    cell.statusMessage.text = self.dataSource[indexPath.section][indexPath.row].statusMsg
  }
}

 

다른 제약 조건들은 생성할 때 init에서 1번만 호출되므로 문제가 없다.

동적으로 제약 조건을 추가할 때는 변수 사용을 적극 권장한다.