티스토리 뷰

버그 리포트 #11 에 올렸던 내용으로,

NSAttributedString이 문제인 줄 알았으나 결국은 (아니나 다를까) collection view의 잘못이었던 문제에요.

간단히 살펴보면 아래와 같습니다.

(Bug Report Issue #11 https://github.com/Sueaty/PixelPalette/issues/11 )

 

## 문제상황

오른쪽과 왼쪽이 다른 것 보이시나요? 첫번째, 두번째 cell을 자세히 보면 보이실 것 같아요~!

두 상황 모두 비정상이에요. 언제나 하나의 레이블만 highlight 되어야 하거든요.

cell의 배경색에 따라, 밝으면 아래 label에 어두우면 위 label에 highlight가 됩니다.

 

전 highlight를 위해 NSAttributedString을 사용했는데요,

간단히 코드로 살펴볼게요!

func setUI() {
    let whiteHighlight = [NSAttributedString.Key.backgroundColor: UIColor.white]
    let blackHighlight = [NSAttributedString.Key.backgroundColor: UIColor.black]
    if color.isLight {
        let attributedString = NSAttributedString(string: hexLabel.text ?? "",
                                                  attributes: blackHighlight)
        hexLabel.attributedText = attributedString
    } else {
        let attributedString = NSAttributedString(string: nameLabel.text ?? "",
                                                  attributes: whiteHighlight)
        nameLabel.attributedText = attributedString
    }
}

 

## 언제 문제 상황이 발생하는가?

특정 상황에서 발생하는 것이 아니라 랜덤하게 발생하는 문제였어요.

언제는 의도한 대로 나왔다가, 언제는 전부 말썽이었다가...

reload를 해도 될때가 있었고, 안 될 떄도 있었죠.

 

## 시도 1 : NSAttributedString이 불안정한가?

처음 든 생각은 NSAttributedString에 대한 의심이었어요.

(이유는 몰라도) NSAttributedString이 view rendering에 어떤 간섭을 해서 제대로 view가 업데이트가 안되나보다 싶었죠!

그래서 색을 칠하는 방식에 문제가 있다면, 다른 방법으로 칠해보자 생각했어요.

쓰고 있는 방법이 NSAttributedString.Key.backgroundColor 였는데 이 대신

label의 layer에 접근해서 background 색을 입히는 label.layer.backgroundColor 방식을 택해봤어요.

결과는 당연하게도 실패였어요. 오히려 constraint가 깨지는 문제까지 발생하더라구요.

 

## 시도 2 : prepareForReuse

prepareForReuse에서 attributedText를 nil로 설정해야겠다는 생각은 공식문서를 다시 확인한 후에야 할 수 있었어요.

사실 prepareForReuse에서 cell에 있는 component들을 재사용 전에 reset 해 놓는게 당연하거든요?

그런데 예전에 썼던 글이 기억에 남아서 마지막 보루처럼 남겨놓고 있었어요.

바로 이 글입니다.

2021.05.17 - [CS/Swift & ios] - [Rx] Reusable Cell의 흔적이 남는다

 

[Rx] Reusable Cell의 흔적이 남는다

Tistory에는 요약본이 올라 와 있습니다. Syntax Highlighting으로 편하게 읽고 싶으신 분들은 여기서 읽으시면 되어유~ [노션 바로가기] 문제 상황 각 cell마다 Image와 Like Button이 존재한다. 버튼을 눌러..

sueaty.tistory.com

 

prepareForReuse function에 대한 description이 tableview와 collectionview 따로따로 존재합니다.

위의 저 글을 쓸 때는 tableview에서 말썽이 생겼던 것이거든요?

그래서 tableview section에 작성 된 prepareForReuse를 참고했었는데 이렇게 적혀있었어요.

To avoid potential performance issues,
you should only reset attributes of the cell that are not related to content,
for example, alpha, editing, and selection state.
The table view's delegate in tableView(_:cellForRowAt:) 
should always reset all content when reusing a cell.

 

즉, tableView(_:cellForRowAt:)이 cell을 재사용 할 때 안의 content를 초기화시키니

content와 무관한 속성들만 prepareForReuse 에서 초기화시키라는 내용이죠.

그래서 당시에 전 "UI component들의 속성도 이곳에서 초기화하면 안되는구나" 라고 생각했었어요.

 

 UICollectionReusableView 밑에는 이렇게 쓰여있어요.

Don’t use this method to assign any new data to the view;
that’s the responsibility of your data source object.

 

이 글을 읽고 나서야 제가 이전에 잘못이해했음을 깨달았어요.

위에서 말한 'content'가 결국은 'data source' 였던 것이죠... 쿄쿄

 

이 한 문장을 읽고나니 문제는 너무 쉽게 해결되었습니다.

 

## 해결 : prepareForReuse

prepareForReuse에서 각 label의 attributedText를 nil 값으로 설정해주면 그만인 셈이었던거에요!

그래서 아래와 같이 단 몇 줄의 코드로 해결되었답니다~ 룰루!

override func prepareForReuse() {
    nameLabel.attributedText = nil
    hexLabel.attributedText = nil
}
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함