Cocos2d-x 클라이언트에 아이템 종류를 하나 더 넣었다. 상점 목록에 나오고 구매도 되는데 InventoryLayer 에서는 빈칸으로 보였다.
Table of contents
Open Table of contents
늘린 곳과 안 늘린 곳
enum ItemType 에 한 줄 넣고 ShopLayer 쪽 switch 에도 넣었다. 인벤토리 쪽에도 같은 모양이 있었고 거기는 안 건드렸다.
const char* invIcon(ItemType t) {
switch (t) {
case ITEM_WEAPON: return "inv_weapon.png";
case ITEM_ARMOR: return "inv_armor.png";
case ITEM_POTION: return "inv_potion.png";
}
return ""; // 새 값은 여기로 온다
}
grep -rn "ItemType" --include=*.cpp 로 찾으니 일곱 군데였다. 아이콘과 정렬 순서와 판매 가능 여부와 창고 보관 여부와 효과 적용과 UserDefault.xml 저장 형식과 서버 전송 코드다. 일곱을 다 고쳐야 새 종류 하나가 완성된다. 한 군데를 놓치면 그 기능만 빠진다.
조용히 빠지는 것이 문제였다
빈 문자열을 돌려주면 GCC 가 아무 말도 안 하고 실행도 된다. CCSprite 가 빈 이름으로 만들어져 화면만 이상하다.
빠진 값을 눈에 띄게 만들었다. CCLOG 를 남기고 물음표 그림을 돌려준다. 빈칸은 못 알아채도 그것은 알아챈다.
컴파일러가 잡게 했다
default 를 아예 빼면 GCC 가 빠진 값을 경고한다. -Wall 에 들어 있는 -Wswitch 다.
warning: enumeration value 'ITEM_COSTUME' not handled in switch [-Wswitch]
default 가 있으면 이 경고가 안 나온다. 안전해 보이는 default 가 검사를 없애는 것이다.
-Wswitch-enum 이라는 것도 있었다. 이쪽은 default 가 있어도 빠진 값을 짚어 준다.
warning: enumeration values 'ITEM_ARMOR', 'ITEM_POTION', and 'ITEM_COSTUME'
not explicitly handled in switch [-Wswitch-enum]
다만 이건 모든 switch 에 다 걸려서 시끄러웠다. 켜지 않았다.
그래서 switch 를 두 부류로 나눴다. 모든 값을 반드시 처리해야 하는 곳은 default 없이 두고 -Wswitch 에 맡긴다. JSON 으로 받은 값처럼 모르는 값이 들어올 수 있는 곳은 default 로 받고 CCLOG 를 남긴다. 앞쪽이 다섯이고 뒤쪽이 둘이었다.
표로 모으는 방법도 봤다
switch 를 일곱 군데 두는 대신 한 곳에 모으는 방법도 봤다.
static const ItemMeta ITEM_META[] = {
{ ITEM_WEAPON, "icon_weapon.png", "inv_weapon.png", 10, true },
{ ITEM_COSTUME, "icon_costume.png", "inv_costume.png", 40, false },
};
새 종류가 줄 하나가 되고 빠뜨릴 자리가 없다. 전부 옮기지는 않았고 값을 돌려주기만 하는 것은 표로 갔으며 조건에 따라 계산이 들어가는 것은 분기로 남겼다.
enum 값을 배열 첨자로 쓰는 자리도 같이 봤다. ITEM_TYPE_MAX 를 쓰고 있으면 따라 늘지만 숫자를 직접 박아 뒀으면 새 값에서 범위를 넘는다. 그건 CCAssert 로 막았다.
정리
- 열거형에 값을 늘리면 그 값을 분기하는 모든 자리가 대상이다
- 한 곳만 고치면 나머지는 조용히 빠진다
- 빈 값을 돌려주면 오류가 안 나고 화면만 이상하다
default를 빼면-Wswitch가 빠진 값을 경고한다-Wswitch-enum은default가 있어도 잡지만 모든switch에 걸려 시끄럽다- 안전해 보이는 기본 분기가 그 검사를 없앤다
- 모든 값을 처리할 분기와 모르는 값을 받을 분기를 나눈다
- 값을 돌려주기만 하는 분기는 표로 모으면 새 값이 줄 하나가 된다
- 열거형을 배열 첨자로 쓰면 크기 상수도 같이 본다