오랜만에 티타임을 가졌다. 하루 밖에 안지났는데,.. 벌서 기억나지 않는 것들이 너무 많다.. -_-;;.. 일단 생각나는 대로 정리!
Alloy 이슈들
Alloy 1.2 버전부터 ListView를 XML로도 정의할수 있게됐다. 물론 ListView는 아직 한창 개발중이기 때문에 drag 이벤트라든가 headerView나 Pulldown Refresh 기능들은 좀더 기다려야한다. 자세한 내용은 Alloy Jira 페이지를 확인해보자.
ListView에 데이터 바인딩시 삽질하기 쉬운 착각들
1. 먼저 dataCollection은 ListView가 아닌 ListSection에 정의해야한다.
이 문제 때문에 삽질한 시간은 정말 눈물 겹다. TableView의 경우 dataCollection을 TableView에 정의 하지만 ListView 조금 다르다. 다음 예제를 보자. 아래와 같이 ListView에 dataCollection을 정의하면 Alloy 컴파일 오류를 발생시킨다.
<ListView dataCollection='잘못된정의'>
<Templates>
<!-- 여기에 여러 템플릿을 정의 할수있다. -->
<ItemTemplate name="tpl1" />
<ItemTemplate name="tpl2" />
</Templates>
<ListSection></ListSection>
</ListView>
따라서 dataCollection은 반드시 아래와 같이 ListSection에 정의하도록 하자!! dataCollection으로 지정된 값은 models 폴더에 정의된 파일명과 동일한 콜랙션을 바인딩하게 된다. 아래 예제는 posts 콜랙션을 리스트뷰 템플릿에 바인딩하게 된다.
<ListView>
<Templates>
<ItemTemplate name="tpl1"></itemtemplate>
<ItemTemplate name="tpl2"></itemtemplate>
</Templates>
<!-- 데이터 바인딩시 dataCollection 속성은 필수 인자다. -->
<ListSection dataCollection='posts'></ListSection>
</ListView>
2. dataTransform과 dataFilter 속성의 차이점.
데이터 바인딩시 dataCollection 속성과 더불어 설정할 수 있는 2가지 속성이 더 있는데, 바로 dataTransform과 dataFilter 속성이다. 이 두 속성은 모두 아래와 같이 함수를 지정해야한다.
<ListView>
<Templates>
<ItemTemplate name="tpl1"></itemtemplate>
<ItemTemplate name="tpl2"></itemtemplate>
</Templates>
<!-- 데이터 바인딩시 추가로 dataTransform과 dataFilter를 지정할 수 있다. -->
<ListSection dataCollection='posts' dataTransform='doTransform' dataFilter='doFilter'>
</ListSection>
</ListView>
두 함수의 차이는 간단하다. dataTransform 속성은 ItemTemplate에 데이터를 입힐 때 실행되는 함수로써 바인딩되는 콜렉션의 모델을 인자로 받아 가공할수있다. 반면에, dataFilter는 콜랙션 자체를 필터링 할때 사용한다.
3. 데이터 바인딩시 반드시 ListSection에 ListItem을 지정해라!
흔히 착각하는 것중에 하나가 ListSection을 비워두면 “초기에 아무런 값이 없고 나중에 동적으로 채워 넣을수 있겠지?” 하는 생각인데, ListView 자체를 컨트롤러에서 동적으로 직접 create해서 생성하는 경우에는 맞는말이다. 하지만 데이터 바인딩을 한 경우에는 반드시 아래와 같이 ListItem을 지정해야하고, 이렇게 지정된 녀석이 콜렉션의 갯수만큼 반복 된다는 사실을 잊지말자!
<ListView>
<Templates>
<ItemTemplate name="tpl1"></itemtemplate>
<ItemTemplate name="tpl2"></itemtemplate>
</Templates>
<ListSection dataCollection='posts' dataTransform='doTransform' dataFilter='doFilter'>
<!-- 콜랙션을 반복하면서 아래에 정의된 아이템을 한벌로 생성한다. -->
<ListItem template="tpl1"/>
<ListItem template="tpl2"/>
</ListSection>
</ListView>
성능 이슈
Alloy 이외에 일반적인 성능과 관련된 이야기들이 있었다. 정리하면 다음과 같다.
1. class 아니죠! className 입니다.
TableViewRow의 속성으로 같은 템플릿으로 구성되는 행들을 같은 className으로 지정해야 내부적으로 재활용하게 된다. class와 className을 헷갈리는 경우가 있으니 철자에 주의하자!
2. 디바이스 정보를 얻어오는 API는 한번만 호출하자!
Ti.Platform.xxxx 형태의 API는 비용이 비싸므로 반드시 로컬변수에 사용할 값을 캐시해서 사용한다.
var DEVICE_WIDTH = Ti.Platform.displayCaps.platformWidth;
3. 윈도우를 생성할 때 주의할 점.
윈도우는 비싼 비용을 지불하고 만드는 녀석이다. 특히 컨테이너로서 윈도우 안에 많은 뷰나 컨트롤들이 올라가게 되고, 이벤트를 바인딩 했다가 해제를 제대로 못하는 경우엔 메모리누수가 생길수가 있다. 따라서 습관적으로 윈도우가 닫힐때 $.destroy()를 실행시켜주자.
$.window.addEventListener("close", function(){
// 특히, dataCollection 메소드를 이용해 데이터 바인딩을 한 경우 반드시 실행해야한다.
$.destroy();
});
4. 다중 윈도우를 이용해 뷰를 구성할때 주의할 점.
FaceBook과 같은 레이아웃을 구성할때는 가장 밑단에 깔리는 리스트 뷰는 매번 생성할 필요가 없다. 다만 쓰기나 상세 보기처럼 잠깐 나왔다가 사라지는 윈도우라면 매번 생성해되 윈도우가 닫힐때 걸린 핸들러를 잘 해제해준다. 위 3번 참고.
5. 이미지를 다룰때는 반드시 ImageView에 올리자.
캐시하는 방법은 Image_Best_Practices 문서를 참고한다.
6. 전역 이벤트 리스너를 윈도우와 혼합할때 생기는 메모리 누수
다음 코드처럼 동적으로 생성한 컨테이너를 전역 이벤트 리스너에서 사용한 경우 절대 지워지지 않는다! 주의하자!
var someFunction = function() {
var table = Ti.UI.createTableView(),
label = Ti.UI.createLabel(),
view = Ti.UI.createView();
Ti.App.addEventListener('bad:move', function(e) {
// table은 지역변수지만 앱이 종료되기 전까지 해제되지 않는다.
table.setData(e.data);
});
view.add(table);
view.add(label);
return view;
};
그밖에 ACS 이슈들..
1. ACS에서 있는 데이터를 fetch 할때 ORDER를 따로 지정하지 않으면, 랜덤하게 넘어오므로 ORDER를 지정하자.
2. ACS에 RESTful API는 구현되어 있으나 Ti.Cloud 객체에 구현되지 않는 객체도 있다.
3. 서버 이슈를 클라이언트로 끌어들이지 말자!