'ios'에 해당되는 글 12건

  1. 2020.03.04 20200304
  2. 2020.02.14 20200214
  3. 2017.06.13 자산 관리 앱 리뷰 (2)
  4. 2017.06.01 WKWebview
  5. 2016.02.15 Missing iOS Distribution signing identity for...
  6. 2016.02.06 SFSafariViewController 버그
  7. 2015.11.13 CoreData iCloud 연동 관련
  8. 2015.11.10 iOS SafariViewController 세로 고정

20200304

개발 2020. 3. 4. 21:09

GeometryReader to the Rescue

  • SwiftUI로 개인 프로젝트를 진행할 때 GeometryReader를 사용하면 가끔 앱이 크래시되는 일로 인해 원인을 파악하려고 삽질을 했지만 원인을 알 수 없었던 적이 있다. GeometryReader에 대해 자세히 알아보기 위해 읽게 되었다.

Inspecting the View Tree – Part 1: PreferenceKey

  • 위의 아티클을 읽으면서 Recursive하게 읽게 된 아티클.
Posted by 52
TAG ios, swift, SwiftUI

댓글을 달아 주세요

20200214

개발 2020. 2. 14. 18:20

Cleaning Up With Swift Defer

  • defer 가 2개 이상일 때의 우선 순위에 대해 생각해 본 적이 없었다. 애초에 defer를 두 번 쓴다는 생각을 하지도 않았고 그럴 상황이 있을까? 싶긴 한데 이런 생각 조차 해본적이 없었다는 것이...

Xcode UI Testing Cheat Sheet

  • 요사이 UITest를 추가해야 할 필요성을 절감(...)해서 조금씩 찾아가면서 하고 있었는데 프린트해서 옆에 놓고 해보고 싶을 정도로 잘 정리가 되어있었다.
Posted by 52
TAG ios, log, swift, Xcode

댓글을 달아 주세요

가계부를 정리하면서 자산 관리를 해야 겠다는 생각이 들어 iOS용 앱을 찾아보니 크게 KB마이머니, 뱅크샐러드, Broccoli 라는 앱을 찾을 수 있었다. 세 가지 앱을 모두 설치해 보고 느낀 점을 간단히 정리해 놓는다.



KB 마이머니

* 국민은행에서 만들어서 그런지 가장 다양한 금융자산 관리가 가능하다. (은행/카드/보험/증권/현금영수증/부동산/자동차/금/은/외화현찰 등등등.. - 국내 대부부분의 금융기관은 다 등록되는데 펀드슈퍼마켓의 자산은 관리를 못한다. 왜????) 지출을 관리함으로서 가계부의 역할도 할 수 있다지만 주 목적은 자산관리.

* iOS6s plus 환경의 해상도를 지원하지 않는다. 그래서 화면 자체가 큼직큼직한데 이는 장점이자 단점이 될 수 있을 듯. 개인적으로는 화면을 넓게 쓰지 못하기 때문에 단점으로 보인다.

* (찾지 못했을 수도 있지만) 앱 실행 과정이 셋 중 제일 번거롭다. 매번 공인인증 비밀번호를 치고 들어가야 함. 공인인증서 로그인 시 [빠른 로그인] 이라는 항목이 보이긴 하다만 선택해도 달라지는 점이 보이지 않았다. 나머지 두 앱은 Touch ID 로그인까지 지원하여 비교적 편하게 접근이 가능하다.

* 자동으로 정리된 지출 내역을 손 좀 보려다가 아래의 이유로 포기.


네이버 페이로 결제한 것은 어디서 무엇을 샀는지에 관계 없이  

'네이버페이_이니시스' 라고 표시되는데 

일괄변경밖에 안되니 항목별로 관리를 할 수가 없다. 



Broccoli

* 3종류의 앱 중 UI / UX 면에서는 제일 깔끔했다.

* 가계부 특화라기 보단 마이머니처럼 종합 자산 관리가 주 목적으로 보이는데 마이머니에 비해 자동으로 연동할 수 있는 자산의 규모가 적다. (은행/카드/현금영수증). 증권이나 부동산 등등은 수동으로 입력하여 관리해야 함.

* (내가 찾지 못한 것일 수도 있지만) 지출 내역이 카드만 집계되어 보인다. 그래서 가계부 용도로는 애매함.

* 그런데 소비 이력이나 소비 분류는 제일 깔끔함. 셋 중에서 가장 잘 분류해주는 것 같다.



혹시 몰라 민감할 수 있는 정보는 자체 삭제 처리;;;


뱅크샐러드

* 자산 관리보단 가계부에 최적화 된 앱.

* 기능적으로 봤을 때는 세 앱 중에서 가계부 관리에는 가장 좋다.

* 다만 실 사용하기가 불편할 정도로 여기저기 버그가 보인다. 

    * 내역 수정 시마다 서버와 통신을 하게 되는데 이게 먹통이 되어 내역이 반영이 안된 상태로 그대로 있는 경우가 자주 발생 

    * 카테고리 내역 수정 / 분류 수정 시 잘 되는 경우도 있고 계속 먹통인 경우가 많다.

    * 카드 사용 내역 연동이 불안정하다. (나의 경우는 네이버 체크 카드의 지출 내역이 제대로 넘어오지 않음. 이것 저것 만져보다가 설정에서 '숨김 자산 관리' 기능으로 네이버 체크 카드를 숨긴 후 다시 활성화 한 이후에 이런 듯 한데, 이후 계정을 완전히 삭제 후 다시 생성해도 마찬가지다. -  이는 좀 더 지켜봐야 하는데 현재 시간 부에 뱅크샐러드, Broccoli 둘 다 신한 카드 연동 시 연동 오류를 내고 있어서 신한 카드쪽 연동 이슈로 인한 문제일 수도 있다만 Broccoli의 경우는 오류가 났어도 지출 내역은 제대로 가지고 온 상태.)

        * 카테고리 수정 시 아래와 같이 같은 카테고리가 중복되어 보이는 문제도 있다.


 

정리하자면-

* 종합 자산 관리를 원하면 KB마이머니가 셋 중에서는 최고.

* 가계부 정리에 특화된 앱을 원한다면 뱅크샐러드가 제일 나아보이나 아직은 버그가 상당함.

* Broccoli 는 세 가지 앱 중에서는 UI/UX는 제일 좋으나 기능면으로 봤을 땐 어중간.

* 뱅크샐러드와 Broccoli의 경우 가입 후 초기 진행 과정 및 금융/카드사 등록의 UI/UX가 꽤 유사하다. 잘 모르면 같은 곳에서 만들었다고 착각할지도;;;


나는 KB마이머니와 뱅크샐러드를 설치하여  KB마이머니로는 종합자산관리를 하고, 가계부 관리는 뱅크샐러드를 이용하되, (성실하게;;;;) 버그 및 개선 의견을 이메일로 전달하면서 앱의 버그가 사그러들기를 기대하기로 했다. Broccoli는 백업으로 사용하면서 기능 개선 요소를 계속 체크해 보기로 함.

Posted by 52

댓글을 달아 주세요

  1. 박휘홍 2017.06.14 14:39  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 고객님 뱅크샐러드 고객지원팀 박휘홍입니다 ^^
    고객님이 작성하신 자세한 리뷰 너무 감사히 읽었습니다 :)
    먼저 불편을 드려서 죄송합니다ㅠ
    며칠간 서버에 문제가 있었는데 현재 서버 최적화가 완료되어
    내역/카테고리 수정시 전혀 문제가 없습니다!
    또한 숨김한 기간동안 내역이 잘 불러오지 않으시다면 죄송하지만
    내 금융상품관리 -> 해당 카드사 우측의 톱니바퀴 -> 연동 해제
    를 통해 연동해제를 했다가
    다시 연동해주시면 정말 감사드리겠습니다 ^^

    앞으로도 고객님이 놀랠만한 기능들을 준비중이니 기대해주세요 :)
    뱅크샐러드는 고객님들과 함께 서비스를 만들어 나가고 있습니다.
    사용중 불편사항이나 개선점이 보이시면 언제든지
    카톡 플러스 친구 '뱅크샐러드'로 연락 주시면 정말 너~무 감사 드리겠습니다

    • BlogIcon 52 2017.06.17 14:16 신고  댓글주소  수정/삭제

      이렇게 답글을 달아주셔서 감사합니다! 개발자로서 이렇게 좋은 서비스를 기획하고 만들고 있다는 점이 부럽습니다. :) 좋은 서비스를 만들어 주신 덕분에 가계부 관리가 즐겁네요. 앞으로도 좋은 서비스 부탁드립니다!!

WKWebview

개발 2017. 6. 1. 19:41

iOS8부터 제공되는 Webkit기반의 웹브라우징을 위한 Framework이다.


WKWebview는 많은 delegate를 갖고 있는데 크게는 uiDelegate와 navigationDelegate로 나눌 수 있으며 오늘 끄적이고자 하는 부분은 navigationDelegate에 대한 부분이다.


navigationDelegate를 통해 WKWebview가 웹 navigation을 하면서 발생하는 이벤트들을 관리할 수 있다. 몇 가지 중요한 delegate를 나열해 보자면 didStartProvisionalNavigation(content가 webview에 load 되기 시작할 때 호출), didFinish(navigation이 완료되었을 때 호출), decidePolicyFor...(정책 제어를 통해 navigation accept / deny를 제어할 수 있음) 등이 있다.


뭐 여기까지는 나도 잘 알던 내용인데, 며칠 전에 WKWebview를 통해 웹 페이지 로딩 시 로딩되는 모든 페이지가 저 delegate를 타는 건 아니라는 사실을 알게 되었다. 


기본적인 WKWebview를 이용하여 'http://www.reddit.com'(모바일 버전)을 불러올 경우 모든 페이지가 정상적으로 불려진 이후 didFinish delegate가 호출되며 완료되는 것 까지는 문제가 없다. 그런데 이 상태에서 콘텐츠 링크를 터치하면 다른 사이트처럼 사용자가 터치한 주소를 로딩 시작해서 didStartProvisionalNavigation부터 decidePolicyFor... delegate를 호출하면서 정책을 체크하고 didFinish로 끝나야 할 것 같지만 전혀 아무런 delegate도 호출되지 않는다. 아마도 SPA(Single page application) 기반의 웹이 이러한 이슈를 가지고 있는 것 같았다.


WKWebview를 이용하여 웹 페이지를 보여주고 사용자의 history를 저장하는 기능을 만들던 나는 살짝 멘붕에 빠졌고 구글링을 했지만 쉽게 답을 찾을 수 없었다. 나와 같은 상황에 빠진 사람이 없나? 싶을 정도로 답이 없어서 내가 뭘 잘못했나 싶어 미친 듯이 코드를 째려봤다만 아무런 답을 얻을 수 없었다.


결국 이러한 몇몇 웹에 대해 API 문서상으로 제공하는 방법으로는 해답을 찾지 못했으나 약간 우회하여 얻을 수 있는 방법을 찾을 수는 있었는데 observer를 통한 방법이었다.


WKWebview의 경우 몇몇 이벤트를 observer를 통해 받을 수 있는데 'estimatedProgress', 'loading', 'title', 'canGoBack', 'canGoForward'의 5가지는 잘 알고 있었지만 'URL'이라는 항목이 있었다는 것은 이번에 처음 알게 되었다.


webView.addObserver(self, forKeyPath: "URL", options: .new, context: nil)


위처럼 'URL'을 추가하면 delegate를 통해 오지 않는 url navigation event를 추가적으로 받을 수 있으며, swift 3.x기준으로 


override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)


위의 method를 통해 받을 경우 keypath가 "URL"로 change[.newKey] 값이 URL 형으로 현재 navigation 중인 주소 정보를 받을 수 있게 된다. 물론 webView 인스턴스를 사용할 수 있다면 webView의 현재 url을 받아도 같은 주소를 얻을 수 있다.


나만 몰랐던 것일 수도 있지만 누군가에게 도움이 될 수 있기를 기대하며 기록해 놓는다.

Posted by 52

댓글을 달아 주세요

iTunes Connect에 앱을 올리려고 하니까 'Missing iOS Distribution signing identity  for...' 관련 에러가 발생했다. 갑자기 왜 이러나 싶어 인증서를 새로 발급받고 온갖 삽질을 했지만 문제는 애플에서 제공하는 인증서의 2016/2/14일부로 만료되어서 발생하는 문제였다.


"Uploading archive error: "Missing iOS Distribution signing identity  for..."


조치로는 만료된 WWDR 인증서를 지우고, 다음 경로에서 (링크) 2026년까지 유효한 새 인증서를 받아 갱신하면 된다.


애플에서의 공지도 있었다.


Apple Worldwide Developer Relations Intermediate Certificate Expiration


이런 사실도 모르고 엄한 인증서들만 지우고 받고 삽질을 했다. 

Posted by 52

댓글을 달아 주세요

iOS용 갈무리 UI/UX 변경 및 엔진 개선 작업 막바지에 매번 내 아이폰에서만 테스트하다가 소영의 아이폰으로 테스트를 했는데 SafariViewController로 웹 페이지를 연 후, Swipe to Dismiss 동작으로 창을 닫으면 그 후론 앱이 먹통이 되어버리는 문제를 발견했다.


내 아이폰에서는 발생하지 않아서 코드에 문제가 있나 싶어 열심히 디버깅을 해 봤는데 SafariViewController를 통해 웹 페이지를 연 후, 좌상단 Done 버튼이 아닌 Swipe to Dismiss 동작으로 창을 닫은 다음 다시 SafariViewController를 열려고 시도하면 Freeze 되는 것을 확인했다. 좀 더 정확히 이야기하면 Swipe to Dismiss 제스처를 사용하여 SafariViewController를 닫으려고 한 이후부터 제대로 ViewController가 소멸되지 않고 먹통이 되기 시작하는 것이었다. 그래서 내 쪽 코드의 문제는 아니라는 것을 확인한 후 검색해 보니 iOS 9.2.x 버전의 버그다.


링크 : SFSafariViewController in iOS 9.2


해당 Thread의 댓글을 보면 임시 해결책을 제시하고 있다. 일단 Swipe to dismiss 제스쳐를 강제로 막아야 하는 것이 관건인데 NavigationController 안에 Safari ViewController를 우겨넣어(!) 버리고 띄우는 방법이다.


Posted by 52

댓글을 달아 주세요

iCloud를 이용한 Coredata 사용은 굉장히 단순해서 편해 보이지만, 많이 답답하다. 


Coredata 저장을 iCloud를 이용하도록 설정하고 난 후에는 진행 상황에 대한 피드백을 얻을 수 있는 방법이 없어 난감한 경우가 생긴다. 이번에 그러한 사례를 두 건 만나게 되어 기록해 놓는다.


앱이 시작되고 iCloud 저장소를 통한 Coredata를 설정이 시작되면 로그창에서 아래와 같은 로그를 확인할 수 있다.


Using local storage: 1


이 상태는 아직 완전히 iCloud를 통한 Coredata 사용 준비가 완료된 상태가 아니다. iCloud 저장소에 연결되기 전에 임시로 생성된 로컬 스토리지를 사용하고 있다는 의미이다. (링크)


저 1의 값이 0으로 바뀌어 로그창에 찍혀야 모든 준비가 끝난 상황이다. 그런데 개발자 입장에서 'Using local storage : 0'이 찍히는 상태, 다시 말해 사용 준비 완료된 상태를 체크할 수가 없다. 내가 만든 앱에서는 'Using local storage' 값이 0으로 바뀌는 것에 대한 통지를 받을 수 있는 방법이 없다는 말이다. 물론 일반적인 상황에서는 저 값이 1이든 0이든 상관하지 않고 쓰면 되지만 초기화 과정에서 오류가 발생했을 때가 문제다.


진행 과정 중에 문제가 발생하면 앱에 피드백을 해주면 좋은데 디버그 시 디버그 창에 오류가 발생했다는 메시지와 함께 60초 후, 또는 120초 후에 재시도를 한다는 로그가 뜰 뿐이다.  디버그 창에 나오는 메시지가 아니라면 앱은 오류가 발생했지만 그 상황을 인지하지 못하고 그저 iCloud가 잘 돌아가고 있겠거니- 하고 있을 뿐이다.


시작 시 초기화 하는 과정에서 문제가 발생하는 사례가 두 건이 있었다.


1. 앱 강제 종료 후 다시 실행 하였을 때 iCloud를 사용하기 위한 초기화 실패

: 'failed finishing setup for store during asynchronous iCloud initialization~' 가 포함된 로그를 확인할 수 있다. 저런 에러 메시지 이후 60초 이후 다시 시도 한다고 하는데 60초 지나 다시 실행해도 같은 오류가 발생하며 그 다음엔 120초 후에 다시 실행하겠다는 메시지를 볼 수 있다. 120초 후에도 역시나 오류가 발생한다. 이 상황에서 앱을 다시 한번 강제 종료한 이후 재 실행하면 최초 실행 시 초기화 하는 작업을 진행하여 정상적인 상태가 된다.


검색해 보면 iCloud 서버와 동기화를 하거나 또는 동기화할 데이터가 남아있는 상황  - 어떤 transaction이 완전히 완료되지 않은 상태 -  에 강제종료를 하는 경우 이런 상황에 빠지게 되는 것으로 보이는데 조치법을 열심히 찾아봤지만 'ManagedObjectContext의 내용 변경 시 performBlock이나 performBlockWait를 사용하는 비동기 방식을 사용하여 최대한 그런 상황을 만들지 말라.' 가 일반적인 내용이었다. 하지만 완벽한 해결책은 아니다. 더 큰 문제는 저 상황에 빠졌을 때 앱 입장에서는 iCloud가 오류를 냈는지 알 수가 없기 때문에 대처할 수가 없다는 점이다.


2. 최초 실행 시 초기화 실패

: 'initial sync notification returned an error (Error Domain=BRCloudDocsErrorDomain Code=12 "The operation couldn’t be completed. (BRCloudDocsErrorDomain error 12.)")' 와 비슷한 로그를 확인할 수 있으며 60초 후에 다시 시도한다는 메시지가 나온다. 다행히 이 경우는 60초 후 재 시도시 대부분 정상적으로 초기화가 완료된다. 그런데 그 60초 동안이 문제다. 앱 입장에서는 60초 후에 재 시도하는 상황에 대해서 전혀 알 수가 없다. 앱이 실행하자마자 iCloud 저장소의 내용을 복원해야 하는 상황에서 60초나 아무런 반응이 없다면 (개발시엔 로그창에라도 찍히나 일반적인 사용자의 경우는 아무런 정보를 받지 못한 상황에서) 이래저래 난감하다. 하다못해 iCloud 서버 동기화 준비 중이라는 메시지라도 사용자에게 보이고 싶지만 이 역시 완벽한 해결책을 찾을 수 없었다.


며칠 이와 관련한 해결책을 고민하다가 1번의 경우는 앱 종료 시 appdelegate 내의 applicationWillTerminate 에서 앱을 처음 실행할 때 기기 내의 iCloud 저장 공간을 생성하고 초기화 할 수 있도록 로컬에 생성된 파일을 날려버리는 무식한 방법 말고는 아직 해결책을 찾지 못했고 2번의 경우는 '최초 실행 시' 라는 가정하에 준비 완료된 상황을 잡을 수 있는 방법을 찾을 수 있었다.


일반적인 상황에서는 몇 가지 정보를 받아볼 수 있도록 되어 있는데 Notification으로 다음의 세 가지 상황을 받아 볼 수 있긴 하다.


* NSPersistentStoreDidImportUbiquitousContentChangesNotification : iCloud에 저장된 데이터가 변경되었음을 알림

* NSPersistentStoreCoordinatorStoresWillChangeNotification : 저장소의 데이터를 변경할 것이라고 알림.

* NSPersistentStoreCoordinatorStoresDidChangeNotification : 저장소의 데이터가 변경되었다고 알림.


여기서 NSPersistentStoreCoordinatorStoresDidChangeNotification 을 통해 알려주는 정보 중 'NSPersistentStoreUbiquitousTransitionTypeKey'라는 키로 좀 더 자세한 상황을 받을 수 있다는 것을 알게 되었다. 


    NSNumber *transitionType = [notification.userInfo objectForKey:NSPersistentStoreUbiquitousTransitionTypeKey];

    int theCause = [transitionType intValue];

    

    switch (theCause) {

        case NSPersistentStoreUbiquitousTransitionTypeAccountAdded: {

            NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountAdded");

            // account was added

        }

            break;

        case NSPersistentStoreUbiquitousTransitionTypeAccountRemoved: {

            NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountRemoved");

            // account was removed

        }

            break;

        case NSPersistentStoreUbiquitousTransitionTypeContentRemoved: {

            NSLog(@"NSPersistentStoreUbiquitousTransitionTypeContentRemoved");

            // content was removed

        }

            break;

        case NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted: {

            NSLog(@"NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted");

            // initial import

        }

            break;

            

        default:

            break;

    }



NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted 가 저장소 초기화가 완료되었다는 정보인데 이를 체크하면 최초 실행 시 초기화되는 시점을 확인할 수가 있다. 이 Notification이 온 후에 'Using Local Storage : 0'으로 바뀌면서 준비가 완료된다. 그나마 다행인 점은 최초 실행 시 문제가 없다면 대부분의 경우 다음 실행 시에는 같은 오류가 발생하는 일은 없어 보인다는 점이다. (강제 종료 시 1번 상황이 발생하지만 않는다면)


iCloud를 이용하는 앱이 한 두개가 아닌데 내가 발견한 문제에 대한 완벽한 해결책이 보이지 않는 것으로 보아 일반적인 상황은 아니고 아마도 나의 잘못된 iCloud 사용 방법이 문제가 아닌가 라는 생각을 하고 있다. 그래서 놓친 부분이 있을까 싶어 Using the SQLite Store with iCloud 문서를 차근차근 읽어보는 중이다.


그렇다고 하더라도 진행상황에 대한 피드백이 미흡하다는 점은 아쉽고 답답하다.




Posted by 52

댓글을 달아 주세요

갈무리 앱을 사용하는 유저께서 폰 자체의 화면 고정 기능과 상관없이 앱 자체에 세로 고정 기능을 넣어달라는 요청이 왔다. 아마도 화면 방향 고정을 해제한 상태에서 앱을 사용하는 경우 조금만 흔들려도 화면이 가로세로로 왔다갔다 하는 것이 불편하기 때문에 요청하셨던 것으로 보인다.


그래서 작업을 시작했다. 


ViewController 기반의 Class에서 


- (BOOL) shouldAutorotate

- (UIInterfaceOrientationMask) supportedInterfaceOrientations


를  Override 하여 작업을 해야 하는데, 갈무리 앱의 경우는 게시물 리스트가 보이는 MasterViewController에서 위의 두 함수를 Override 한다고 해도 아무런 변화가 없다.


화면에는 보이지 않지만 UINavigationController가 화면 구성의 시작이기 때문에 이 부분을 수정해야 하기 때문이다. 상속받은 Class를 만들고 위의 두 함수를 Override 하여 세로 고정과 관련한 코드를 추가한 후, StoryBoard상의 루트인 NavigationViewController를 새로 만든 Class로 교체하여 세로 고정 기능을 완성했다.


수정 후, 테스트를 하다 보니 근래에 iOS9 환경에서 게시물을 SafariViewController로 볼 수 있도록 기능을 추가했었는데 이 SafariViewController는 세로 고정이 되지 않는 것을 알게 되었다. 아이폰 가로 보기 상황에서 게시물 리스트는 세로 고정으로 나오는데 게시물은 가로로 나오는 이상한 상태. 어찌 보면 당연한 현상이다.


이 역시  SafariViewController를 그대로 사용하지 말고 이를 상속받은 Custom Class를 만든 후, 위에 언급한 두 개의 함수를 Override 하니 해결이 가능했다.


안드로이드 버전 갈무리에도 같은 기능을 추가해 봐야겠다.

Posted by 52

댓글을 달아 주세요