2017년 8월 16일 수요일

2017년 7월 5일 수요일

[ios] Interface Builder에 GMSMapView를 추가했더니 런타임 에러...

맵뷰를 쓸일이 있어서 XIB에 GMSMapView를 추가 했는데,
아래와 같은 오류가 나오고 크래쉬 ㅠ_ㅜ
Unknown class GMSMapView in Interface Builder file.
검색 해보니,
1. Clean Build
2. XCODE 재기동
3. 앱 재설치
4. derived file 삭제
라는데, 정말 어이 없게도 1번을 한뒤 2번을 하니 됨 -ㅁ-;;

2017년 4월 20일 목요일

[ios] 코어 애니메이션 설명 변역

코어애니메이션에 대해
코어 애니메이션은 어플리케이션의 컨텐츠를 관리 한다.
코어애니메이션은 드로잉 시스템 그 자체는 아니다. 어플리케이션의 콘텐츠를 이미지의 현태로 합성하고 하드웨어에서 조작 하기 위한 기반이다. 그 핵심이 레이어오브젝트로 이것을 이용해 콘텐츠를 관리, 조작 하는 것이다. 콘텐츠를 비트맵의 형태로 집어 넣어 그래픽 처리 하드웨어가 쉽게 조작 가능하도록 하는  기능이 있다. 대다수의 어플리케이션에서 레이어는 뷰의 컨텐츠를 관리 하는 수단으로서 사용 되지만, 필요한 경우 뷰와는 독립적으로(스탠드얼론) 레이어를 생성하는 것도 가능하다.

레이어에 변경을 가하면 애니메이션이 기동된다.
코어애니메이션에서 생성한 애니메이션의 대부분은 레이어의 프로퍼티에 변경을 가하면 기동 되게 된다. 레이어 오브젝트에는 뷰와 동일하게 bound와 화면상의 위치 불투명도, 좌표변환행렬등의 외관에 관여하는 다양한 프로퍼티가 있고, 이 값을 변경 할 수 있게 되어 있다. 프로퍼티의 대부분은 값을 변경 하면 원래의 형태로 부터 새로운 행태로 옮겨지는 암묵적인 애니메이션이 시작된다. 명시적으로 애니메이션화 하면 움직임을 자세하게 제어할 수 도 있다.

레이어는 계층화해서 관리 할 수 있다.
레이어를 계층화해서 부모자식 관계를 정의 할 수 있다. 이 관계는 컨텐츠의 외관에 영향을 가져와 뷰와 동일하게 관리 할수 있다. 뷰에 연결된 레이어의 계층은 뷰의 계층을 그대로 반영한 것이 된다. 더욱이 스탠드얼론인 레이어를 계층에 추가하므로써 뷰와는 독립적으로 콘텐츠를 표시 하도록 확장할수도 있다.

액션을 구현해 레이어의 디폴트 동작을 변경 할 수 있다.
암묵적 레이어 애니메이션은 액션오브젝트를 사용해 실행된다. 이것은 통칭 오브젝트로 간단한 인터페이스를 구현하고 있다. 코어애니메이션은 이 액션오브젝트를 이용해 디폴트 애니메이션 모음을 레이어에 포함하고 있다. 한편 독립적으로 액션 오브젝트를 구현하면 표준과는 다른 형태의 애니메이션도 구현 가능 하다. 이것을 레이어에 적당한 프로퍼티에 연결하면 해당 프로퍼티의 값이 변화할때 코어애니메이션이 이 액션오브젝트를 검색해 기동 하도록 되어 있다.

코어애니메이션의 기초
코어애니메이션은 어플리케이션을 구성하는 뷰외의 시각적요소에 움직임(애니메이션)을 더하기 위한 범용 시스템이다. 뷰에 교체되는 것은 아니다. 뷰와 통합해서 드로잉 성능을 개선함과 동시에 콘텐츠의 움직임을 더하기 위한 기술이다. 이것을 실현하기 위해 뷰의 내용을 비트맵의 형태로 캐슁하고 그래픽 처리 하드웨어가 직접조작 할 수 있도록 한다. 경우에 따라 캐슁을 위한 콘텐츠를 표시 관리 방법을 변경해야 할 수도 있지만 대다수의 경우 코어애니메이션의 존제를 의식할 필요조차 없다. 코어애니메이션은 더욱이 개개의 시각 콘텐츠를 간단한 방법으로 특정할수 있도록 해 이를 뷰에 통합하고 애니메이션을 표시하는 역할을 맡고 있다.
코어애니메이션을 이용하면 뷰나 시각오브젝트의 형태변화를 애니메이션으로 표시 할수 있다. 이 형태변화의 대부분은 시각 오브젝트의 프로퍼티변경에 대응한다. 이를테면 뷰의 위치, 크기, 불투명도와 같은 프로퍼티가 변경된다고 생각해 보자. 이러한 프로퍼티에 변경을 주면, 현재의 값에서 새로운 값으로 변하는 과정이 애니메이션으로 표시되는 것이다. 코어애니메이션은 보통 (책에 그림을 그려 빨리 넘겨서 애니메이션을 표시하는 것처럼) 뷰의 콘텐츠를 초당 60개로 쪼개는 식으로는 사용하지는 않는다. 화면에서 이동, 페이드인/페이드아웃, 좌표변환을 가하거나 시각속성을 변경 하는등의 경우에 사용한다.

레이어는 드로잉이나 애니메이션의 기반이다.
레이어오브젝트는 3차원 공간에 놓여진 2차원의 면으로 코어 애니메이션의 핵심에 해당한다. 뷰와 동일하게 지오메트리, 콘텐츠, 시각속성등을 관리 하지만, 독립된 "외관"을 정의 하는 것은 아니다. 비트맵에 관한 형태정보를 관리 할 뿐이다. 이 비트맵은 뷰에 대응하는 드로잉의 결과로써 얻어지는 경우와 특별히 지정한 고정이미지의 경우가 있다. 때문에 어플레케이션의 주 레이어는 주로 데이터를 관리 하기 때문에 모델 오브젝트라 생각할수 있다. 애니메이션의 동작에 영향을 주므로 이점을 확실히 이해할 필요가 있다.

레이어베이스 드로잉 모델
대다수의 레이어는 실제론 드로잉처리를 행하지 않는다. 어플리케이션쪽에서 준비한 콘텐츠를 비트맵의 형태로 읽어 들여 캐슁한다. 이 비트맵을 "백킹스토어(Backing store)"라 부르기도 한다. 이후 레이어의 프로퍼티를 변경해도 레이어오브젝트의 상태정보가 변할뿐이다. 이 결과, 애니메이션이 기동되면 코어애니메이션은 해당 레이어의 비트맵이나 상태정보를 그래픽 드로잉 하드웨어에 넘겨준다. 그러면 하드웨어는 새로운 정보에 기반해 비트맵을 드로잉한다. 비트맵 조작을 소프트웨어가 아닌 하드웨어로 하면 엄청나게 빨라진다.
레이어베이스의 드로잉은 고정된 비트맵을 조작한다는 점은 기존의 뷰베이스의 드로잉과 일맥상통한다. 뷰베이스의 경우 뷰 자신에 변화를 주면 해당 뷰의 drawRect:메소드가 호출되어 새로운 파라메터를 바탕으로 재드로잉 하게 된다. 하지만 이것은 메인스레드의 CPU를 사용하기 때문에 부하가 크게 된다. 코어애니메이션은 이를 가급적 피하기 위해 캐슁된 비트맵을 하드웨어를 조작해 동일한 드로잉 결과를 얻고자 한다.
가능한한 캐슁된 콘텐츠를 사용하지만 처음에 그 콘텐츠를 전달해 수시갱신을 행하는 것은 어플리케이션측의 역할이다. 레이어 오브젝트에 콘텐츠를 전달하는 방법은 몇가지가 있다. 자세한것은 "레이어의 콘텐츠를 병합"항목을 참조.

레이어베이스의 에니메이션
레이어오브젝트의 데이터나 상태정보는 화면상의 표시와는 분리해서 관리한다. 이결과 코어애니메이션이 중간에 있어 현재의 상태로 부터 새로운 상태로의 변화를 애니메이션으로 표시 할수가 있는 것이다. 이를테면 레이어의 위치 프로퍼티를 변경 하면 코어 애니메이션은 그 레이어를 현재 위치로 부터 지정된 새로운위치로 이동시킨다. 다른 프로퍼티를 변경한 경우에도 그에 따른 애니메이션을 시작한다. 그림 1-2는 레이어에 적용 가능한 애니메이션를 몇개 표시 하고 있다. 레이어 프로퍼티중 값이 변하면 애니메이션가 발생하는 것을 "애니메이션 가능한 프로퍼티" (85페이지) 라고 한다.
애니메이션 과정에서는 코어애니메이션이 프레임별로 하드웨어 이미징처리를 모두 행한다. 어플리케이션쪽은 애니메이션의 개시점과 종료점을 지정하기만 하면 된다. 타이밍정보나 각종 파라메터도 지정 가능한데, 적당히 디폴트 값이 정해져 있어 필수는 아니다.
애니메이션을 기동하는 순서, 파라메터를 지정하는 방법은 "레이어콘텐츠의 애니메이션화" (42페이지)를 참고.

레이어오브젝트는 자신의 지오메트리를 관리한다.
레이어는 콘텐츠를 시각적으로 표시하기 위해 지오메트리를 관리 한다는 역할도 있다. 구체적으로는 콘텐츠 이미징 영역의 경계나 화면상의 위치, 좌표변환(회전, 확대축소등)에 관한 정보다. 뷰와 동일하게 레이어도 프레임Rect나 경계Rect가 있어, 이것을 사용해 레이어나 그 콘텐츠의 위치를 결정하게 된다. 더욱이 뷰에는 없는 프로퍼티로 앵커점(조작을 행할 중심점)이 있다. 그외에도 지오메트리에 관해 뷰의 경우와는 다른 항목이 몇가지 있다.

레이어는 2종류의 좌표계를 이용한다.
레이어는 포인트베이스좌표계와 단위좌표계의 2종류로 콘텐츠의 배치를 지정 하도록 되어 있다. 전달하는 정보의 종류에 따라 나눠 사용하자. 포인트베이스좌표계는 화면상의 좌표에 직접대응하는 값을 지정하거나 position프로퍼티와 같이 다른레이어를 기준으로 지정하는 경우에 사용한다. 한편, 단위좌표계는 다른 무언가의 값을 기준으로 상대치를 갖고 있어 화면상의 좌표와는 연관지을수 없는 경우에 사용한다. 가령 레이어의 anchorPoint프로퍼티는 해당 레이어 자신의 경계를 기준으로 지정하지만, 이 경계의 좌표는 언제라도 변할 가능성이 있다.
포인트베이스 좌표는 레이어의 크기 (bounds프로퍼티)나 위치 (position프로퍼티)의 지정에도 사용한다. bounds에는 레이어자신의 좌표관계를 규정하는 역할이 있어, 레이어가 화면상에 차지하는 범위에선 이 좌표계로 위치를 지정가능 하다. 한편 position프로퍼티는 레이어의 위치를 새로운 레이어의 좌표계로 표시한다. 레이어에는 frame프로퍼티도 있는데 bounds및 position의 값으로 부터 계산가능하기에 실제론 그다지 사용하지 않는다.
bounds나 frame으로 표시되는 사각형의 방향은 플렛폼이 규정하는 디폴트 방향과 일치한다. 그림 1-3에 iOS와 OS X의 방향에 관해 bounds rect의 디폴트 방향을 표시 한다. iOS는 좌상단 OS X는 우하단이 원점이다. 코어애니메이션용 코드를 iOS와 OS X에서 공용하는 경우 이 차이를 고려하지 않으면 안된다.
그림 1-3에 나타난것 처럼 position프로퍼티는 레이어의 중앙을 나태낸다. 이 정의는 anchorPoint프로퍼티의 값에 따라 변한다. 앵커포인트는 몇몇 조작의 좌표원점을 나타낸다. (자세한 것은 "앵커포인트는 지오메트리 조작에 영향을 미친다" (16페이지)를 참조)
앵커포인트는 단위 좌표계에서 지정하는 프로퍼티의 하나이다. 코어애니메이션은 일반적으로 레이어의 크기에 따라 값이 변할 수 있는 프로퍼티에 단위 좌표계를 사용한다. 취급 할수 있는 값의 볌위전체를 기준으로한 비율을 0.0에서 1.0의 값으로 표현한 좌표계이다. 이를 테면 x축을 따라 좌측 좌표는 0.0, 우측 좌표값은 1.0이 된다. y축은 플렛폼에 따라 방향이 다르다. (그럼 1-4참조)
포인트베이스좌표, 단위좌표계 모두 좌표값을 모두 부동 수숫점으로 표시 한다. 따라서 정수로는 표현 할수 없는 정밀한 위치도 지정가능 하다. 인쇄시나, 레티나 디스플레이에 드로잉할때 등 1포인트가 복수의 픽셀에 대응하는 경우에 유용하다. 디바이스의 해상도와는 관계 없이 필요한 정밀도로 지정하면 되기 때문이다.

앵커포인트는 지오메트리 조작에 영향을 미친다
지오메트리가 관계하는 조작은 레이어의 앵커 포인트가 기준이 된다. 이점은 anchorPoint프로퍼티로 접근/지정 가능 하다. 앵커포인트의 영향이 현저하게 나타나는 것은, 레이어의 position프로퍼티나 transform프로퍼티를 조작할때 일것이다. position프로퍼티는 항상 앵커포인트를 기준으로 하는 상대값으로 지정한다. 변환(transform)도 앵커 포인트를 기준으로 행해진다.
그림1-5에 앵커포인트를 변경한 경우 레이어의 position프로퍼티에 어떠한 영향이 있는가를 표시 한다. 부모의 영역 내에서 레이어가 이동하지 않음에도 불구하고 앵커 포인트를 레이어의 중앙에서 경계원점으로 옮기면 position프로퍼티의 값도 바뀌어 있다.

2017년 3월 7일 화요일

[JSON] josn에 인덴트 넣거나 josn에 따옴표 탈출문자 넣어 문자열로 만들어 주는 웹 툴

아래 주소로 들어가면 된다.
http://www.freeformatter.com/json-formatter.html#ad-output

option1에 붙여 넣기 해도 되고
option2에 파일을 업로드 해도 됨

인덴트를 스페이스나 탭으로 넣을지 고를수 있는데,
자바 스크립트를 고르면
" 이런 따옴표를 \" 으로 바꿔준다.
완전 편리함 ㅎㅎ

2017년 2월 27일 월요일

[IOS][swift] UICollectionView, UICollectionViewFlowLayout의 마지막 row만 이상하게 나오는 문제

와 진짜 이건 너무 하다 싶다
UICollectionView로 FlowLayout을 세로로 해서 작업중인데,
유독 마지만 라인만 뭔가 이상하다..

이렇게 나오는데 뭐 이유도 모르겠고 미치는 줄..
검색 해보니 Apple의 버그라는데..
IOS6부터 있었나 본데, 그럼 이건 버그가 아니고 스팩 아님?
여튼 수정 하려면,

class TestLayout: UICollectionViewFlowLayout {
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributes = super.layoutAttributesForElements(in: rect)
        let contentSize = collectionViewContentSize
        return attributes?.filter { $0.frame.maxX <= contentSize.width && $0.frame.maxY < contentSize.height }
    }

}

이런식으로 서브클래스를 생성해서 이 클래스를 레이아웃으로 지정해 주면된다.
아래는 참고한 스택 오버 플로우 링크
http://stackoverflow.com/questions/12927027/uicollectionview-flowlayout-not-wrapping-cells-correctly-ios

[IOS][InterfaceBuilder] Xcode에서 xib파일 작업중 Assistant 윈도우로 연결된 파일이 보이지 않을때..

Xcode에서 xib 파일 작업중 갑자기 잘되던 file's owner 파일이 표시 되지 않는다.
실수로 뭔가 바꿨나 해서 이것 저것 살펴 보고 코드 롤백도 해보았지만 여전히 먹통..
혹시나해서 derived data를 지우니 된다!!!
(Xcode를 완전히 지운 다음 derived data 삭제 하자)
Xcode를 재기동 하면 바로는 안뜨고 몇초 기다리니 떴다 (당황하지 말자)
어쨌든 나쁜 Xcode

2017년 2월 21일 화요일

[IOS][SWIFT] UIPageViewController 크래쉬


아래 처럼 죽는 경우가 발생

2017-02-22 13:29:28.984 PageTest[87046:5081125] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'The number of view controllers provided (3) doesn't match the number required (1) for the requested transition'

* 원인 
setViewControllers([vc1, vc2, vc3], direction: .forward, animated: false, completion: nil)
첫 번째 인자에 필요이상의 뷰컨트롤러를 할당함

* 수정
setViewControllers([vc1], direction: .forward, animated: false, completion: nil)
vc1만 할당 하고 나머지는 DataSource에서 처리 하도록 함

    public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let index = vcs.index(of: viewController)
            else { return nil }

        if index < 1 {
            return nil
        } else {
            return vcs[index - 1]
        }
    }

    public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let index = vcs.index(of: viewController)
            else { return nil }

        if index + 1 >= vcs.count {
            return nil
        } else {
            return vcs[index + 1]
        }
    }