목록 화면을 열 때 잠깐 멈췄다.
Table of contents
Open Table of contents
전부 만들고 있었다
쓰던 판에는 목록 위젯이 없었다. CCLayer 위에 CCNode 를 얹고 터치로 위치를 옮기는 식으로 직접 만들었다.
for (int i = 0; i < items.size(); i++) {
ItemCell* cell = ItemCell::cellWithItem(items[i]);
listNode->addChild(cell);
}
보이는 것은 열 개쯤인데 addChild 를 백 번 한다. 아흔 개는 화면 밖이라 아무도 안 본다. 각 칸이 CCSprite 를 들고 있어서 만들 때 이미지를 백 번 읽는다.
보이는 것만 만들었다
스크롤 위치에서 보이는 범위를 계산해 그 범위만 만들게 했다.
int first = scrollY / cellHeight;
int last = first + visibleCount;
열 몇 개만 만드니 여는 것은 빨라졌다. 그런데 이번에는 스크롤이 버벅였다. 위로 나간 것을 버리고 아래로 들어온 것을 새로 만드니 그 비용이 스크롤로 옮겨 간 것이다.
만든 것을 재사용했다
만들고 버리는 대신 위로 나간 것을 보관했다가 아래로 들어올 때 내용만 갈아 끼웠다.
void ItemCell::setData(Item* item) {
m_label->setString(item->name);
m_icon->setTexture(
CCTextureCache::sharedTextureCache()->addImage(item->iconPath));
}
만드는 개수가 보이는 수와 여유 몇 개로 고정된다. 스크롤을 오래 해도 그 개수에서 안 늘어난다.
이미 있던 캐시
이미지 캐시도 따로 만들 생각이었는데 CCTextureCache 가 이미 하고 있었다. addImage() 는 경로를 키로 먼저 찾아보고 없을 때만 파일을 읽는다. 두 번째부터는 원래 빨랐던 것이다.
느린 것은 처음 읽는 순간이었다. addImageAsync() 로 스크롤 방향 두세 개 앞을 미리 읽게 했다. 다른 스레드에서 읽고 콜백은 메인에서 오니 그 사이 화면이 안 멈춘다. 빠르게 스크롤할 때는 걸지 않았다. 어차피 안 보인다.
결국 셋 중 하나는 안 해도 되는 것이었다. 앞의 둘을 넣고 만져 봐야 다음 병목이 나왔고, 세 번째 자리는 CCTextureCache 가 이미 채우고 있었다. 있는 것을 먼저 보는 편이 빨랐다.
정리
- 목록에서 전부 만들면 여는 데서 멈춘다
- 보이는 범위만
addChild한다 - 스크롤할 때마다 만들면 이번에는 스크롤이 느리다
- 만든 것을 재사용하면 개수가 고정된다
- 재사용할 때는
setString과setTexture로 내용만 갈아 끼운다 CCTextureCache::addImage()는 경로를 키로 이미 캐시한다- 느린 것은 처음 읽는 순간이고
addImageAsync()로 미리 읽는다 - 스크롤이 빠르면 미리 읽기를 멈춘다. 어차피 안 보인다