번역자 : 위 글은 2년전(2014년)에 쓰여진 글임에도 번역한 이유는, 이 개념을 알면 수월하고 모르면 해맬 수 있기 때문입니다. 그렇게 대단한 이야기는 아닐지 모르지만 부모와 자식 뷰 간의 터치 이벤트를 주고 받는 일이 있다면 꼭 한번 읽어보길 추천합니다. 


Hit-Test은 한 점(터치 포인트와 같은)이 화면에 그려진 그래픽적인 오브젝트(UIView와 같은)를 관통하는지 결정하는 프로세스이다. 가장 앞쪽에 올라와 있는 view가 무엇인지 알아내기 위해 iOS에서는 Hit-Test라는 것을 사용한다.  Hit-Test는 역방향 우선순위 깊이우선 탐색(Reverse Pre-Order Depth-First Travesal) 알고리즘을 이용하여 view 계층을 조사하도록 구현되어 있다.

Hit-Test가 어떻게 동작하는지 설명하기 전에,  Hit-Test이 언제 호출되는지부터 알아보자. 아래 다이어그램은 손가락이 화면에 터치되는 순간부터 다시 들어올리는데까지 터치 과정의 큼직큼직한 플로우(high-level flow)를 보여준다.


위 다이어그램에서 보여주듯, 화면을 터치하는 매 시간마다  Hit-Test가 호출된다.  Hit-Test 이전 시점에는 어떤 view나 gesture recognizer가 UIEvent 객체를 받는데, 터치가 어느 지점에서 됬는지 그 event에 표현된다.

Note : 알 수 없는 이유로 Hit-Test가 한번에 여러번 호출된다. 이미 결정된 Hit-Test view도 비슷한 현상이 일어난다.

Hit-Test가 끝나고 나면 터치 포인트 아래 최상단 view가 결정된다. 그  Hit-Test view는 터치 이벤트 순서(began, moved, ended, cancelled)의 모든 UITouch 객체와 연관되어있다. 추가적으로  Hit-Test view에서 view나 조상 view들에 붙은 어떤 gesture recognizer들도 위의 UITouch와 연관되어있다. 그러면  Hit-Test view는 터치 이벤트를 순서대로 받기 시작한다. 한가지 염두하고 있어야 할 것은 손가락을 움직여  Hit-Test view의 범위(bounds)를 넘어 다른 view로 움직여도  Hit-Test는 터치 이벤트 순서가 끝날 때까지 모든 touch들을 받고 있을 것이다.

" 그 Touch 객체는 후에 터치가 view 바깥으로 움직여 나갔더래도 그 라이프 타임 동안에는  Hit-Test view와 연관되어있다."

앞에서 말했듯  Hit-Test은 역방향 우선순위(Reverse Pre-Order)의 깊이우선 탐색(Depth-First Travesal)을 사용한다. (먼저 root 노드를 탐색하고 그 다음 높은 index에서 낮은 index 순서로 자식 노드를 탐색한다.) 이런 종류의 탐색은 반복적인 탐색을 줄여주고, 터치포인트가 포함된 view를 내림차순으로 깊이 우선으로 검색하다가, 결과물을 찾으면 찾는 과정을 멈춘다. 이것이 가능한 이유는 subview가 항상 superview보다 위에서 그려지고(render), sibling(형제) view는 subviews 배열 안에서 index가 낮은 sibling view 보다 위에 그려지기 때문이다. 따라서 특정 포인트에 여러 view가 겹쳐져 있으면, 가장 깊은 view 중에 가장 오른쪽 view가 최상단 view가 될 것이다.

"시각적으로 subview의 요소는 subview의 parent view의 모든것을 가리거나 일부분을 가린다. 각 superview는 순서를 가지는 배열로 그것의 subview들을 가지는데, 그 순서는 각 subview의 상태에 따라 배열에 영향을 준다. 만약 두 sibling subview가 서로 겹쳐있다면 마지막에 추가된 subview가 다른 subview 위쪽에 나타나 있을 것이다."

아래 다이어그램은 view 계층 tree에 관한 예제이고, 화면에 그린 UI에 매칭시켜 놓은 것이다. 왼쪽에서 오른쪽으로 정렬된 tree branch들은 subviews 배열의 순서를 의미한다.


위에서 볼 수 있듯이, View A의 자식인 View A.2와 View B의 자식인 View B.1은 서로 겹친다. 그러나 "View B"의 subview index가 "View A"보다 크므로 View B와 그 subview들은 View A와 그것의 subview들보다 위에 그려진다. 그러므로  사용자의 손가락이 View B.1과 View A.2가 겹치는 부분을 터치하여 Hit-Test를 하게되면 View B.1이 반환된다. 

Depth-First Travesal in Reverse Pre-Order 방식을 적용함으로써 가장 깊은 내림차순으로 터치 포인트가 포함된 view를 찾으면 탐색을 멈춘다.


이 탐색 알고리즘은 UIWindow에 hitTest:withEvent: 메시지를 보냄으로서 시작되는데, UIWindow는 view 계층에서  root view이다. 이 메소드로부터 반환되는 값(view)은 터치 포인트를 포함하는 최상단 view이다.

아래 플로우 차트가  Hit-Test 로직을 설명한다.


그리고 아래 코드는 원래 hitTest:withEvent: 메소드를 실제 구현해본 것이다.


hitTest:withEvent: 메소드는 먼저 터치를 받을 수 있는지부터 확인한다.

view가 터치를 받을 수 있다면:
  • view가 hidden 이 아니여야한다.
    self.hidden = NO;
  • view의 userInteraction이 enable이여야한다.
    self.userInteractionEnable == YES;
  • view의 alpha가 0.01보다 커야한다.
    self.alpha > 0.01
  • view가 포인트를 포함해야한다.
    pointInside:withEvent == YES
그러고 view가 터치 받는 것을 허락하면, 이 메소드는 어떤 어떤 하나가 nil을 반환하기 전까지 높은 곳에서 낮은 곳으로 그것의 각 subview에 hitTest:withEvent: 메시지를 보냄으로서 receiver의 subtree를 탐색한다. 그 subview들에의해 반환된 첫번째 nil이 아닌 값은 터치 포인트를 포함하는 최상단 뷰이고 receiver에의해 반환된다. 만약 모든 receiver의 subview들이 nil을 반환하거나 그 receiver가 suview가 없으면 자기 자신을 반환한다.

다르게말하면, view가 touch를 받지 못하도록 되있을 때는 이 메소드가 더이상 receiver의 subtree를 탐색하지 않고 nil을 반환한다. 그러므로 이  Hit-Test 작업에서는 모든 view들의 계층을 다 탐색하지 않아도 된다는 것이다.

hitTest:withEvent:를 override 하여 사용한 일반적인 유스케이스
한 view가 터치 이벤트 매 순간마다 다른 view에 리다이렉트될 수 있도록 터치 이벤트를 다룰 경우 hitTest:withEvent: 메소드를 override 하면 된다.

" Hit-Test가 호출되기 전에 터치 이벤트 순서 중 첫번째 터치 이벤트가 그것의 receiver에게 보내기 때문에, 이벤트들을 리다이렉트하기위해 hitTest:withEvent:를 override 하는 것은 그 이벤트 순서의 모든 터치 이벤트를 리다이렉트 하게 될 것이다."

View의 터치 면적 넓히기
hitTest:withEvent: 메소드를 override 할 수 있는 또하나의 경우는 view의 터치 범위가 그것의 실범위(bounds)보다 커야할 때 이다. 예를들어, 아래 그림은 20X20 크기의 UIView를 나타낸다. 이 크기는 실제 손가락으로 touch 받기엔 너무 작다. 따라서 그것의 터치 면적을 hitTest:withEvent: 메소드를 override하여 각 방향마다 10px씩 증가시킬 수 있다.



Note : 이 view에대해 정확하게  Hit-Test 하기위해, parent view의 영역(bounds)은 child view의 원하는 터치영역을 포함하고 있거나, 원하는 터치 영역을 포함하기 위해 그것의 hitTest:withEvent: 메소드를 overrid 해야한다.

아래에 터치 이벤트들을 view들에 통과시키기
종종 해당 view의 터치 이벤트를 무시하고 그 view의 아래에 통과시켜야 할 때가 있다. 예를들어, 앱 위에 투명하게 전체적으로 view가 덮혀올라간 경우를 생각해보자. 이 오버레이 는 평범하게 터치를 받을 수 있는 control들과 button들의 subview들을 가질 것 이다. 그러나 어디에서나 오버레이를 터치하면 그 오버레이 아래의 view들에게 터치 이벤트를 넘겨줄 수 있다. 이 동작을 완료하기 위해서는 오버레이에서 터치포인트를 포함하는 그것의 subview들 중 하나를 반환하거나 nil을 반환하기 위해 hitTest:withEvent:를 override할 수 있다. 오버레이 위에 터치가 된 경우에도 마찬가지이다.


subview에 터치이벤트 보내기
또 다른 경우는 parent view의 모든 터치 이벤트를 child view로 보낼때이다. child view가 parent view의 일부분만을 차지하지만 그 parent에서 발생하는 모든 터치들에 반응해야할때 이 동작이 반드시 필요하다. 예를들어, 이미지들이 회전목마처럼 구현된 UI를 생각해보자. parent view로는 UIView, 그 위에 child view로는 UIScrollView를 가지고 이 view는 pagingEnable를 YES로 clipsToBounds를 No로 설정한다. 그 위에 이미지들을 올려 구성한다.


UIScrollView의 내부만 터치를 받는것이 아니라 외부에도 터치를 받고 싶은데, 그 scroll view의 parent view 범위 내로 제한하고 싶을때, 아래와 같이 그 parent의 hitTest:withEvent: 메소드를 override 함으로서 가능하다.





WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

원문https://medium.com/@kazmiekr/what-every-ios-developer-should-be-doing-with-instruments-d1661eeaf64f

Introduction

iOS 프로젝트를 마무리할때, 디바이스에 올려 테스트하여 크래쉬가 없이 잘 돌아가면 만족하고 끝낸적이 있을것이다. 그게 과연 올바른 마무리일까? Instruments를 사용하여 프로파일링(profiling)을 하지 않고 끝냈다면 잘 마무리 했다고 할 수 없다고 생각한다. 그 이유는 개발자 디바이스에서 잘 동작한다해서 실유저에서 크래쉬가 안난다는 보장은 없기 때문이다.

Xcode에는 Instruments라는 퍼포먼스 튜닝 어플이 포함 되 있다. 이 프로그램은 다양한 기준으로 개발자의 앱을 프로파일 할 수 있게 해준다. Instruments는 CPU 사용량, 메모리 사용량, 메모리 누수, 파일/네트워크 활성, 베터리 사용량 등을 측정할 수 있는 툴을 포함한다. 이것들은 Xcode에서 바로 시작할 수 있어서 쉽게 켤 수 있다. 그러나 지금 보고있는 프로파일 자료가 뭘 프로파일링 한건지 잘 모를수도 있으며 이런 상황은 개발자들이 이 깊은 잠재력을 가진 툴 사용을 저해할 수 있다.

이 많은 프로파일 툴 중에 어떤걸 선택해야할까? 먼저, 느려진 네트워크 요청이나 버벅거리는 스크롤과 같은 눈어띄는 퍼포먼스 이슈 해결을 위한 선택지들이 있을 수 있다. 그러나 나는 당신이 생각하기에 모든것이 정상적으로 돌아가는것으로 보이는 부분에서 CPU나 메모리 사용량을 체크해보는걸 추천한다.

프로파일을

이 이야기를 하기 전에 한가지 우리가 염두할 것은, 모든 개발자들이 항상 그들의 앱에 프로파일을 하지는 못한다는 것이다. 대부분은 데드라인과 예상 결과물이 존재한다. 어떨땐 앱을 프로파일링이고뭐고 마감을 빠듯하게 지키는것도 힘들 때가 있지만, 우리는 이런 상황까지 고려하여 '어느 시점에 프로파일링을 하면 좋을까'에 대해 얘기해보고자한다.

최소한 만든 앱을 앱스토어에 제출하기 전에 한번은 프로파일링을 해줘야한다. 당신은 앱스토어의 심사를 통과 한 후 유저들이 앱을 사용하면서 안 좋은 일들이 일어나길 바라지는 않을것이다. 프로파일링을 하지 않았다가 문제가 생긴다면, 좋지 않은 리뷰들이 많아질 것이고 다운로드 수는 감소할 것이다.

나는 당신이 주요 기능들을 끝낸 후에, 재빨리 프로파일을하여 모든것이 정상적으로 동작하는지 확인해보는 것을 제안한다. 만일 재빨리 하지 못하면, 잠재적인 이슈들이 점점 드러날테고, 그것이 한참 쌓이면 완전히 새로운 기획으로 바뀔 수도 있으며 이것은 런칭을 심각하게 미루게 될것이다. 팀으로써 당신은 프로파일하는 시간을 개발 플랜의 일부로 살짝 넣도록 해야한다.

익숙하지 않은 프레임워크를 쓰게되면 Instruments 켜는걸 제안한다. 또한 대부분의 iOS 프레임워크와 라이브러리는 끊임없이 바뀌며, 이런 변화는 당신이 익축하지 않은 프레임워크와 작업하는것과 비슷하다. 대부분 개발자들은 바뀌는게 언제인지 느낌이 올때가 있고, 만약 당신이 그런 느낌을 받았다면 얼른 당신이 만든 작업물들에서도 안정적으로 동작하는지 확인하기위해 프로파일링을 돌려야한다. 당신이 추가한 라이브러리에서 당신의 통제를 범위를 벗어나 발생될 있는 메모리 이슈가 있는지 확인하기 위한 프로파일에는 3rd party 라이브러리를 가져다 쓰는것 또한 좋은 방법이다.


Xcdoe에서 프로파일링

Xcode 이전엔 Instruments 안에 묻어둔 많은 정보를 ‘Debug Navigator(Xcode 기능의 일부)’ 포함하기위해 위해 Instruments 밖으로 확장해왔다. 만일 당신이 6 단축키를 누르면, 앱에 대한 퍼포먼스 정보를 있다. 여기서 CPU/Memory/Energy/Disk/Network 엑티비티의 빠른 요약 정보를 있고 즉각적인 이슈를 수도 있다. 여기서 상단에 보이는 ‘Profile in Instruments’ 버튼을 눌러서 Instruments 실행할 수도 있는데, Instruments를 누르면 디버그 세션으로 이동할지 아니면 새것을 새로 시작할지 물어볼 것이다.

CPU 프로파일링

제일 먼저 우리가 프로파일해볼 것은 CPU 사용량이다. CPU 프로파일링을 시작하기위해 우리는 ‘Profile’ 이라는 프러덕트를 선택하고 타겟은 디바이스 선택해야한다. CPU 프로파일링을 할때, CPU 사용량에 대한 정확한 정확한 정보를 얻기 위해 실제 디바이스를 사용하기를 원할것이다. 만약 시뮬레이터로 타겟을 정하면 실제 디바이스 환경과는 많이 다른 머신의 CPU 정보를 얻게된다. 이상적인 테스트로는 당신의 작업물이 가장 느린 디바이스에서 동작하는지 확인한 뒤에 빠른 환경에서 테스트 하는 것일 것이다.

CPU 프로파일링은 인터벌을 줘서 프로세스들이 동작하는 샘플을 얻어냄으로써 측정한다. 디폴트로 샘플은 1ms 단위로 얻어지지만, 원하면 바꿀 수도 있다. 스냅샷들 사이에서 어떤 프로세스들이 아직 돌고있는지 봄으로써, 그것들이 얼마나 길게 작동되고있는지 측정할 있다.

프로파일 빌드가 끝이나면, Instruments 켜지면서 어떤 템플릿으로 프로파일링을 할지 물어본다. 우리는 CPU 사용량 측정을 위해 “Time Profiler” 것이다.

이것은 Timer Profiler 셋업을 위한 초기 Instruments 화면이다. 이제 실제로 프로파일링을 하기위해 녹화 버튼을 누른다. 가끔 몇몇 이유로 녹화 버튼이 비활성되있는 경우가 있다. 그럴때는 오른쪽 상단에 비활성된 이유가 나타나 있을 것이다. 나는 ‘device is offline’이라는 상태에서 멈춘적이 있는데, 보통 디바이스를 재부팅하면 해결된다. 이제 녹화 버튼을 누르면 당신 앱에서 무슨 일이 일어나는지 정보를 보여주기 시작한다.

상단에는 녹화가 진행되는동안 시간이 지남에 따라 당신의 CPU 사용량 그래프가 보이며 하단에는 동작하는 동안의 프로세스들의 Call Tree 보일것이다. 프로세스의 초기 덤프(dump) Call Tree에서 상단에 보이는 자료들은 매우 쓸때없이 많아 보인다. 또한 이것은 모든 시스템 라이브러리의 활성 상태를 보여줘버린다. 당신은 아마 당신이 작성한 코드에만 집중하고 싶을것이다. 다행히 중요한 정보만 빨리 찾도록 쉽게 설정하는 방법이 있다.

오른쪽에 톱니모양처럼생긴 ‘Display Settings’(2) 누르면 ‘Call Tree’를 위한 옵션들이 나온다. 디폴트로는 대부분 옵션이 오프되 있을 것이다. 우리는 우리가 원하는 것만 켜면 된다. 이제 이 옵션들이 뭘 하는 놈들인지 보자.

  • Seperate by Thread — 많이 사용된 스레드 순서로 프로세스를 보여준다.
  • Invert Call Tree — 스택을 뒤집어서 보여준다. 가끔 유용하게 쓰인다.
  • Hide System Libraries — 시스템 라이브러리 프로세스는 숨기고 당신의 코드만 보여준다.
  • Flatten Recursion — 하나의 개체에서 재귀로 호출된 콜들을 보여준다.
  • Top Functions — 함수 호출이 함수로부터 불려진 함수에 의해 추가적인 시간이 쓰이는지 시간순으로 보여준다. 기능은 무거운 메소드가 어떤건지 찾는데  도움을 준다.

필자는 프로파일링할때 대체로 모두 체크하고 정보를 얻는데, 이게 유용하다. 필터링 옵션선택한 Call Tree 보면, 당신의 앱에 메소드가 CPU 얼마나 사용하는지 쉽게 확인할 수 있다.

이제 CPU 입장에서 무거운 메소드들 리스트를 모니터링 하면서 앱의 정확한 지점을 최적화 시켜볼 있다. 몇몇은 건드리기 힘들 수도 있지만 최적화 가능한 것들도 많이 있을 것이다. 필자는 최적화를 어떻게 하는지에대해서는 깊게 보지는 않을 것이지만 여기 몇몇 생각해볼만한 것들이 있다:

  • 무거운 작업은 UI 프로세스가 아닌 것은 다른 쓰레드로 옮긴다.
  • 항상 다시불러올 필요가 없는 이미지, 데이터 등등의 것들은 캐싱한다.
  • 당신은 필요하지 않는 UI 업데이트를 지도 모른다. UI 업데이트를 줄인다.

한가지 팁은 ‘Call Tree’ 섹션의 오른편에 존재하는 ‘Extended Detail’ 섹션이다. 이것은 당신이 선택한 스택 흔적(trace) 있고 라인을 더블클릭하면 정확히 당신 코드를 찾아 보여줄 것이다. 작은 Xcode아이콘을 클릭하면 동작중인 메소드를 Xcode에서 보여줄 것이다.

퍼포먼스 이슈를 해결하여 업데이트를 시킨 후에는 같은 방식으로 profiler 돌리면서 이전 퍼포먼스보다 나아졌는지 체크한다. 과정을 당신이 만족할 까지 반복하면 된다.

메모리 프로파일링

다음으로 프로파일링 것은 메모리 프로파일링이다. 이것은 직접적인 이슈가 아닐때가 많아서 iOS 개발에서는 그냥 지나쳐버리기 쉬운 것중 하나이다. 만일 당신 앱에 메모리 누수가 발생하고 있는데 유저가 지속적으로 사용한다면 메모리는 점점 꽉 찬 뒤, 결국 아웃 오브 메모리 상황이 발생하여 앱이 꺼지게 것이다. 이런 상황은 당신의 앱한테만 좋은게 아니라 유저의 디바이스 입장에서 메모리 부족으로 다른 앱들에게도 안 좋은 영향을 끼치게 될것이다. 그럼 이제 Instruments 이용하여 어떻게 메모리 누수를 방지를 있는지, 그런 상황에서 어떻게 고칠 있는지 알아보자.

시간이 지남에 따라 메모리 사용량이 점점 증가하는걸 원치 않을 것이다.

아래와 같은 상황은 원치 않는다.

아래와 같은 상황을 원한다.

가장 쉽게 메모리 사용량을 확인하는 방법은 Xcode 안에 있는 ‘Debug Navigator’에서 보는것이다. ‘Memory’ 패널을 선택하고 실시간 메모리 사용량을 있다. 여기서는 메모리 사용량이 계속 증가하거나 한번도 낮아지지 않는 문제와 같은 문제들을 바로 확인하는데 도움을 준다.

메모리 사용량을 자세히 보기위해 ‘Profile in Instruments’ 누르면 세션에서 transfer할건지 새로 하나 만들면서 (Instruments)restart할건지 물어볼 것이다. restart 누른다. 필자는 transfer 눌러서 뭔가 정보를 손실하거나 그런 좋지않은 경험이 많다. 그러면 Allocations and Leaks 템플릿을 가지는 Instruments 열리고 이것은 모든 메모리 할당과 모든 발생하는 잠재적인 누수를 눈으로 있다.

이번에도 누수 부분을 깊게 들어가진 않겠지만, 메모리가 할당은 됬으나 해제가 되지않는 것들을 보기 위해 특정 시간 간격 안에서 스냅샷을 찍어볼 것이다. 메모리 누수는 Objective-C C 라이브러리 같은 것을 사용하면 종종 나타난다. 웬만하면 ‘Analyze’ 빌드 옵션을 사용하여 찾을 있으나, 간혹 Analyze 툴이 아무것도 찾지 못할때도 있다. 반면 Swift에서 작업하고 있으면 Objective-C 사용할때보다 누수를 적게 겪을 것이다.

메모리 프로파일러를 쓰면서 내가 찾은 유용한 기능은 두가지이다. 첫째로 순서가 이후에 동시에 이벤트의 순서를 수행한다는 것. 둘째로 메모리 마킹을 생성하는 것이다. 이걸 사용하면 당신은 스냅샷 사이에 메모리의 변화를 분석할 있다. 오른편 ‘Display Settings’ 섹션 위에 있는 ’Mark Generation’ 버튼을 누르면 바로 메모리 스냅샷을 찍을 수 있다. 진행되는 동안 마크를 만드는걸 까먹었어도 언제든지 마크를 추가한 뒤에 단지 클릭하고 표시를 상단에 놓고 움직이면 원하는 지점으로 마크를 이동시킬 있다. 그러고나서 ‘Allocation Type’ ‘All Heap Allocations’으로 바꾸면, 우리가 손대기 힘든 시스템의 정보들은 숨기고 증가량에 따라서 정렬해준다. 이제 당신은 범위동안의 메모리 사용량을 보기 쉽게 확인할 있을것이나, 이것은 실제 당신이 생성한 오브젝트 자체를 확인하기는 어려울 것이다.

이제 메모리 할당에 따른 리스트는 가지고 있으니, 이것이 제대로 나타나있는지 확인하야한다. 사실 초기에 표시되는 데이터들은 쓸모가 없다. 만약 Swift 사용하고 있다면, 모든 Swift 객체들의 이름 앞에 이름이 붙을것이고 거기서 이름으로 필터링하면 당신의 객체를 찾을 있다. 반면 Objective-C 사용하고 있다면 객체를 찾아내는데 특이한 방법을 사용한다. 당신이 찾고 싶은 것의 이름을 알고 있을것이다. 당신의 파일이나 객체 이름에 접두로 어떤 특정 이름을 붙인다면 찾을 있다. 예를들어 당신의 모든 view controller들이 *ViewController 같은 이름을 가진다면 ‘ViewController’ 검색해도 찾을 있을것이다.

여기 필자가 만든 예제에는 4개의 스냅샷이 있고 ViewController라는 이름으로 객체들을 필터링 했다. 그리고 스냅샷 사이에 ServiceViewContoller에서 누수가 일어났다는걸 있다.

여기 글의 목적을 위해 ViewController에다 뭔가 문제가 있는 retain cycle 집어넣으나, 원래는 코드를 뒤져보면서 어떤것이 객체의 누수를 만드는지 일일히 살펴봐야한다. retain cycle 객체가 서로 강한 참조를 하고있어서 서로 할당 해제되는걸 막을때 일어난다. 필자는 retain cycle에대해 깊게 말하진 않을것이나, 이런 경우에 delegate blocks/closures 먼저 확인하는 것을 추천한다. 당신의 delegates (weak)하고 blocks/closures에서 약한 참조를 사용한다는걸 확인하면 좋을것이다.

당신의 객체에서 다른 객체를 참조하고있어서 그 다른 객체가 메모리 해제되지 못하는지 일일히 확인하기 좀 힘들다면, Instruments 사용하여 많은 객체들의 자료를 얻을 있을 것이다. Instruments에서 객체 옆에 작은 화살표를 누르면, 객체의 모든 할당된 객체들을 보여줄 것이며 누가 생성하였는지까지도 나온다. 그다음 작은 화살표를 누르면 retain release count 정보까지 얻을 있다. 만일 count 0 되지 않는다면 메모리 해제가 되지 않았다는 뜻이다. 여기서 팁을 주자면 ‘Responsible Library’ 당신 코드이니 유심히 보고 ‘libsystem_blocks’ 유심히 봐라. 반대로 ‘UIKit’ 스킵해도 된다. 필터링하기위해 아이템들을 검색 박스에 쳐볼 있다. 그러고나면 ‘ Extended Detail’ 보이고 이것들이 어떻게 돌아가고있는지 스택 trace 보이게 될것이다.

결론

글은 Instruments 아주 일부만 보여준 것이다. 그래도 Instruments 시작하는 사람들에게 도움이 되길 바라며 처음부터 바로 잘하지 못해도 괜찮다. 툴을 사용하는데 점점 익숙해지다보면, 당신의 코드가 나은 코드가 될것이다. 당신은 문제를 만든 이슈를 찾는것에 주도적이게 것이며, 프로파일링이 당신의 익숙한 개발 플랜 하나의 플랜으로 자리잡게 될 것이다.

Instruments에대해 배우고 싶다면 필자는 2014 WWDC 비디오(Improving your app with Instruments) 보는것을 적극 추천한다. 여기서는 추가적인 팁엔 트릭과 함께 살펴볼 있다. Instruments에대해 읽고싶으면 애플이 만든 유저 가이드 확인해보길 바란다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

원문 : medium.com/@mandrigin/ios-app-performance-instruments-beyond-48fe7b7cdf2?source=userActivityShare-d07a45aa48c6-1455001286


iOS 퍼포먼스: Instrument 이상

유저들은 기다리는걸 굉장히 싫어한다. 그들은 앱이 뭔가 초기화 한다는것을 전혀 모른 상태에서 자신들의 업무 처리를 최대한 빠르게 하고싶어한다. 그러므로 앱이 모두 즉각적으로 시작할 있다면 인터페이스가 흐르듯 부드럽게 넘어갈 있다. 퍼포먼스가 나오는 앱은 소프트웨어 마켓에서 경쟁력있는 특징중 하나이다. 개발자로서 앱이 퍼포먼스있게 동작하게 하는것을 자랑스러워하는 것을 원하는것도 이유이다.

그러나 많은 이들이 겪듯 퍼포먼스 최적화는 다루기 어려운 문제이다. 대부분 문제를 직관적으로 접근하기 어렵다. 각기 정리된 측정법 없이는 앱이 느려지는 이유를 알아내는건 매우 어렵다.

당신의 퍼포먼스를 최적화하기 위해서는 데이터에 기반한 결론을 내려야한다. 장에서는 당신의 앱에 서로 다른 부분에서 퍼포먼스 측정 데이터를 어떻게 얻어낼 있는지 보여줄것이다.

파트에서는 아래의 것들을 다룰 것이다.

  • 앱에서의 CPU, GPU, 메모리&베터리 사용량
  • 반응성(리스폰시브니스)
  • 앱시작동안의 시간
  • 유저로부터 퍼포먼스 데이터를 얻는

바로 시작해보자!

CPU, GPU, 메모리&베터리 사용량

첫번째 할일은 CPU, GPU, 메모리를 과하게 사용하는 비효율적인 코드를 찾아내는 일이다. 애플은 일을 하기위한 좋은 (Instruments) 제공한다.

우리가 주로 측정해야할 부분은 아래 4 정도이다.

  • CPU ("Time Profiler" 툴 이용)
  • GPU (“Core Animation” 툴 이용)
  • 메모리 사용량 (“Allocations” 툴 이용)
  • 베터리 소모량 (“Energy diagnostics” 툴 이용)

WWDC 비디오는 당신 앱을 분석하기위한 최고의 정보를 제공한다.
아래는 시작하면서 몇 개 골라보았다:


반응성(Responsiveness)

퍼포먼스 측정(이해 "측정"으로 줄여서 말하겠습니다)에 있어서 다음으로 중요한 것은 UI 반응성이다. 터치 헨들링은 메인 쓰레드에서 발생한다. 메인쓰레드에서 시간이 걸리는 작업을 하면, 앱은 버벅거리게 될것이다.

몇몇 동작은 CPU 사용하지 않는 주제에 시간을 잡아먹기도 한다. 만약 메인쓰레드에서 동기화 콜을 불렀다면, 콜이 얼마나 시간이 걸리는지 알아내는것이 문제를 해결하는 방법일것이다.

시간을 측정하기 위해 로그를 찍어볼 수도 있다.

한가지 다른 방법은 Viber 개발자들이 만든 솔루션으로 나타내는 것이다. 솔루션은 메인 쓰레드 하나를 400ms보다 많이 멈추지 않게 지켜보고, 체크하는 특별한 스레드를 가지고있다.

Testing Responsiveness (from Viber’s presentation at NSSpain)


Testing Responsiveness (from Viber’s presentation at NSSpain)


많은 정보는 발표자료(PDF, 7MB)에서 확인할 있다.

데이터를 이용하여 너무 많은 시간이 걸린 (메인싸레드가 멈추는데에는 400ms정도가 적당한 최대치이며, 보면 많은 정보를 얻을 있다.) 찾아내고, 이것을 최적화 시킬지 메인쓰레드 밖으로 보내던지 해야한다.

시작 시간

다음으로 중요한 측정은 앱의 시작하는데 걸리는 시간이다. 전형적인 유저는 당신의 앱을 오직 몇분만 사용한다. 시작시간은 앱의 이미지에 좋지않은 영향을 준다.
여기 시작의 2가지 경우가 있다.

  • Cold 시작 : 당신의 프로세스가 동작하지 않고, OS 의해 실행된다.
  • Warm 시작 : 당신의 앱은 최소화되나 죽지않는다. 이것은 백그라운드로부터 다시 불러온다.


색션에서는 리소스를 많이 잡아먹는 Cold 시작에 초점을 맞출것이다
아래에 iOS 앱의 시작 순서가 나와있다.


The Application Startup Phases (from the documentation)

1. 시작하는데 걸리는 시간을 측정한다.

우리는 main()에서부터 applicationDidBecomeActive:까지 시간이 얼마나 걸리는지 측정해야한다.

앱의 기능을 보여주면서 시간을 잡아먹게 하지 말아야한다. cold 시작 시간을 1 미만으로 떨어뜨리려고 노력하는 것이 좋다.

2. 시작하는 순서에서 부분별로 측정한다.

보통 시작시간의 전체만 아는 것은 충분하지않다. 어떤 부분에서 시작시간을 느리게 만들었는지 아는것 또한 중요하다.
밑에 보이는 것들이 가장 중요한 부분들이다

  • -[AppDelegate application:didFinishLaunchingWithOptions:] - 콜백은 런칭이미지(혹은 스토리보드) 보여질때 호출된다. 곧바로 메소드로부터 return되면 실제 UI 로딩을 시작한다.
  • -[UIViewController loadView] - 앱에 커스텀 뷰를 불러와야한다면, 여기서 뷰를 초기화하게된다.
  • -[UIViewController viewDidLoad] - 뷰가 불러와졌고, 마지막 초기화의 시간이다.
  • -[AppDelegate applicationDidBecomeActivate:] - UI 이미 초기화되어있지만, 콜백이 끝날때까지 블럭되있다. 메소드는 백그라운드로부터 restore될때 호출된다.

몇몇 매소드가 너무 시간이 많이 걸린다면, 최적화시켜야한다.

3. “under pressure” 시작 시간을 측정한다.

전형적으로 현실과 테스트 환경은 다르다는걸 알아야한다.

당신의 앱은 안타깝게도 "현실세계"에서 작동된다. 유저는 종종 다른 앱에서 당신의 앱을 열기도 한다. “다른 굉장히 무거운 앱일 수도 있다. 당신의 앱이 시작될때 다른 무거운 앱은 백그라운드로 가면서 데이터를 저장하려고 있으며, 그런 상황에서의 시간 측정은 굉장히 중요하다.

그런 테스팅(무거운 다른 앱에서 내 앱을 열어보는)을 통해 예측하지 못한 결과를 만들 수도 있기 때문에, 이전에는 코드가 완벽하게 안정적이다가도, 저런 상황에서는 느려질 수도 있다는걸 명심해야한다.

4. 앱이 이미 시작되었지만 여전히 소용없다.(무슨 의미인지 모르겠습니다)

만약 당신 앱이 곧바로 UI 불러오는것이 무의미한 일이라면, 런칭화면이 끝나지 않을 것이다. 비록 UI 불러와지고 반응이 왔었어도, 불러오는데 준비를 위한 데이터가 필요하며, 또한 역시 시작 시간을 재어봐라.

당신의 유저로부터 측정값을 수집해야한다.

모든 측정은 테스트 환경에서 가능할 것이다. 그것은 반드시 필요하지만 너무 완벽하게까지 할필욘 없다. 만약 당신 앱이 인기있는 앱이라면, 만약 유저들이 해외시장을 기반으로 한다면, 몇몇 유저들은 당신이 예상하지 못한 아주다른 환경을 사용할 수도 있다.

추측하기에 다를 있는 환경들이다.

  • 네트워크 상태
  • 하드웨어
  • 소프트웨어(OS 버전, Jailbreak(탈옥...)
  • 기기의 남은 용량
  • 기타 등등

분명 당신 개발실에서 측정한 것은 모두 안정적인 상태일지라도, 별점하나로 컴플레인("앱이 너무 느림ㅡㅡ") 리뷰를 받을 수도 있다. 어떻게 대처하면 될까?
퍼포먼스 측정의 집합을 정의하고(혹은 KPI) 실유저로부터 얻어와야한다. 이것은 대부분 통계 패키지와 함께 사용할 있다.

아래는 당신의 유저로부터 얻을 있는 KPI 예시들이다.

  1. cold 시작시간
  2. warm 시작시간
  3. 마디별 시작시간
  4. 반드시 서버로부터 다운받아야할 것들의 소요시간
  5. 메인쓰레드가 400ms보다 오래 블럭되는
  6. 메모리 워닝이 일어나는
  7. FOOMS(링크)
  8. UI 블럭되거나 쓰잘때기없는 동작의 길이 

결론

쉽게 설명하자면 퍼포먼스 측정은 Instruments.app 프로그램을 열면서 시작하며, 앞에서 본 것 말고도 다양한게 있다. 몇몇 소개된 방법은 구현하기 쉽지만 어떤건 시간과 노력이 필요할 것이다. 어쨋든 솔루션들은 당신의 퍼포먼스 이슈를 찾고 해결을 위한 모니터링하는데 도움을 줌과 동시에 즐겁게 만들것이다.

별점5 리뷰를 받기를 바란다!


+) 이해하면서 의역을 부분이 많이 있습니다. 잘못 이해한 부분이 있다면 지적해주시면 감사합니다.


WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

invalid Toolchain. New apps and app updates must be built with the public (GM) versions of Xcode 6 or later, and iOS 8 SDK or later. Don't submit apps built with beta software.

앱 개발을 완료하고 앱 검수를 위해 앱을 업로드한다. 그다음 "심사를 위해 제출"을 누를 때 위와 같은 오류가 뜬다면 나의 경우 아래와 같이 해결했다.

원문 : http://stackoverflow.com/questions/32174954/submitting-app-from-building-in-xcode-6-4/32233429#32233429

Apps that you submit should be developed using the latest version of Xcode from the Mac App Store and should be built for publicly available versions of iOS, OS X, and watchOS — except when GM seeds are available. Now Mac App Store's Xcode is 6.4 and OS X Yosemite is Build 14F27. If you user xcode 6.4 on OS X El Capitan, you should follow the steps:

  1. Using Xcode, then archive your project
  2. Open organizer, find your .xcarchive file find .xcarchive file
  3. Right click the xcarchive file, choose [Show package Contents]
  4. Find Products/Applications/XXX.app/Info.plist
  5. then change [BuildMachineOSBuild] value to 14F27, just like this: example
  6. Now, you can go to Xcode->organizer, then 【Submit to App Store】




WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

안녕하세요. 아이폰 앱 개발자 카나피오입니다. 저는 지난 3년간 아이폰 앱 개발을 하면서 모았던 유용한 링크를 공유합니다. 대부분 실제로 사용하고 있는 링크를 선별했고, 필요 없는 링크는 제외했습니다. 또한 최대한 자료를 무료로 제공받을 수 있는 링크만 뽑아보았습니다. 혹시 좋은 링크가 있다면 댓글에 달아주세요! 서로 공유하면 좋으니까요.


디자인 참고
Dailygood Design
디자인 관련 링크 모음 사이트. 유명한 디자인 사이트를 모아놓은게 아니라 필수적인 디자인 사이트를 모아놓았다. 디자인 사이트를 모아놓은 사이트조차 예쁘다. 나는 즐겨찾기 해놓고 종종 들어간다.

Dribbble
앱이나 웹의 UI를 참고할 수 있는 디자인 웹 커뮤니티 사이트. 내가 가장 애용하는 디자인 참고 사이트이기도 하다. 보통 앱 개발을 시작할 때 이 사이트를 켬으로써 화면 기획을 시작하기도 한다. UX보다는 UI 디자인이 많다. 예쁘다.

Pinterest
영감을 얻기 위한 사이트. 앱, 웹, 제품 등등 온갖 디자인들이 있다. 더 나아가 영감을 얻을 수 있는 다양한 작품들도 있다. 카테고리도 다양하게 있어서 자신의 취향에 맞게 팔로우하여 볼 수 있고 자신이 저작권에 상관없이 자료들을 모을 수도 있다.

Behance
어도비사가 만든 디자인 커뮤니티 사이트. 어도비의 지원을 빵빵하게 받는 만큼 자료가 많다. (근데 웹사이트가 좀 느리다ㅠ)

Vimeo
영상 디자인 참고 사이트. 작품성 있는 영상 자료들이 많이 올라가있다. 유튜브와 비슷하지만 용도는 조금 다르다. 훨씬 질 좋은 영상 자료들이 올라가있고 고품질을 지향한다. 나는 앱개발 영상을 제작할 때 주로 사용하며, 앱개발시 모션 그래픽을 참고하기도 한다.


디자인 리소스
Noun Project
아이콘 모음 사이트. 온갖 아이콘이 많이 있다. 하악하악


개발
Google Play Console
구글 개발자 페이지.

iTunes Connect
애플 개발자 페이지.


통계
App Annie
개발자 계정을 연결하여 자신의 앱(또는 다른 앱)의 실시간(1시간 정도의 시간차가 있습니다.) 순위권이나 다운로드 수, 수익, 사용자 리뷰, 앱스토어 피쳐드 등등의 퍼블리싱 정보를 얻을 수 있다.

구글 어널리틱스
구글에서 제공하는 서비스 분석기. 자신의 앱에 코드를 심어 놓으면 실시간 사용자나 누적 사용자, 활성 사용자 등 다양한 사용자 정보의 통계를 확인 할 수 있다. 화면 전환이나 이벤트 등을 등록해놓고 사용자가 얼만큼의 빈도로 이벤트를 발생시키는지 알 수 있다.


참고
아이콘 메이커
1024*1024 크기의 아이콘을 넣으면 개발에 쓰이는 아이콘 크기별로 뽑아준다. 이게 겁나 편하다. 안드로이드, 아이폰, 아이패드, 애플워치 등등 해당 디바이스의 아이콘을 다 뽑아준다.

iOS 폰트 리스트

애플 앱스토어 리뷰 시간
http://appreviewtimes.com/
애플 앱스토어의 앱 리뷰 대기 시간을 평균 내어주는 사이트.


추가
유용한 사이트 모음
https://github.com/etdot/bookmark
좀 더 다양한 사이트 모음. 



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,