Story Notifier


Dev./macOS Dev.

Written by CenoX on 2017. 1. 12. 15:08

Story Notifier v1.0.3


* 이 프로젝트는 Reflection 님의 Story Notifier 를 macOS 용으로 재작성 한 것입니다.

윈도우용은 위 링크에서 다운로드하여주세요.


Swift 3으로 작성하였습니다.


본 앱은 모바일용 어플리케이션 카카오스토리 의 알림을 Mac 에서도 받을 수 있게 하는 앱이며, 로그인 시 수집한 사용자의 ID는 절대로 로그인을 제외한 어떠한 경위로도 사용되지 않습니다. 또한 자동로그인 활성화 시 저장되는 개인정보는 AES256으로 암호화되어 기기 내에 저장되며, 절대 다른곳으로 전송되지 않습니다.


1.0.3 업데이트 안내


- 기존 UI와 자동로그인 기능 복구 및 헤더 변경

> 다시 캡챠없이 로그인 할 수 있게되어 기존 UI로 되돌리고 헤더를 변경하였습니다.

> 캡챠를 요구할 시 따로 처리할 수 있도록 패치할 예정입니다.


- 로그인 완료 시 자동로그인을 묻는 알림창이 윈도우가 닫혀 같이 사라지는 버그를 해결하였습니다.


아래는 UI 사진입니다.







기본적인 UI은 위와 같으며, 알림 주기 설정, 로그아웃, 앱 종료 기능만을 지원합니다


위는 알림 UI입니다.


macOS 에 내장된 알림센터를 사용하며, 보기 클릭 시 자동으로 알림이 온 글로 이동합니다. ( 기본 브라우저에서 KakaoStory 에 로그인해야할 수 있음 )


유의사항


 - 이미 온 알림이 중복으로 올 수 있습니다.

 - 예전에 읽지 않았거나, 중첩된 알림이 한번 더 울릴 수 있습니다.

 - 너무 빠른 주기로 설정하면 어플리케이션이 죽을 수 있습니다.

 - 매번 알림확인을 위해 웹에 연결해야 하므로 온라인 연결은 필수입니다.

 - 단기간 많은 알림이 왔을 경우, 알림이 무시될 수 있습니다.

 - 본 어플리케이션을 사용함으로써 발생하는 문제에 대해 개발자는 책임지지 않습니다.


다운로드


StoryNotifier 1.0.3 Release.dmg


드래그식 설치로 설치하시고 최초실행 시, 어플리케이션 폴더에서 앱을 우클릭 후 열기를 눌러 실행하시기 바랍니다.



고지사항


"Kakao®", "KakaoStory®" are trademarks fo Kakao Corp.

CenoX is not affiliated with Kakao Corp. in any ways.


About Kakao's trademarks policy,

See https://developer.kakao.com/policies/trademark


도움 주신 분들


Shift

Reflection

GyungDal


사용한 라이브러리


Sparkle - 공식 홈페이지, Github 프로젝트



[Jubeatbook Qubell] 테스터 모집


Dev./shiftstudios

Written by CenoX on 2016. 6. 3. 13:25

이 페이지는 더 이상 유지보수 되지 않습니다!

새 사이트로 방문해주세요.

https://cenox.co/jubeatbook/


프로젝트 [팀 리창인생] 

Jubeatbook Qubell 의 기능을 테스트해주실 테스트 유저분들을 찾습니다!

2016.11.29 수정 - 패키지 명 변경에 따른 제목 변경


이제 트위터로 TestFlight 초대를 받지 않습니다


테스트는 OBT가 아닌 CBT로 진행되며, 15명 정도만 모집할 예정입니다!

2016.09.01 수정 - 테스트 모집 인원 제한 삭제


Discord 를 통해 alpha 챗을 운영하고 있으니, Jubeatbook 의 테스팅을 희망하시는 분은 여기를 눌러 alpha 챗에 참여하신 후, emails-ios 에 Apple ID를 적어 수시로 초대하는 방식으로 테스팅을 진행할 듯 합니다. ( 안드로이드 또한 링크로 참여 가능합니다! )

2016.11.12 수정 - 테스트 방식 변경 및 트위터 관련 고지



테스트 항목


- 각 테스터들의 계정을 통해 앱의 전체적인 안정성 평가

- 오역 등의 번역 문제 등

- 플레이어의 음악 기록이 정렬된 뷰에서 특정 조건의 나열이 잘 작동하는지 확인

- iOS 서열표의 작동확인


버그 리포팅은 @CenoX_Kang 으로 멘션주시면 감사하겠습니다!

만약 테스팅 중 앱이 팅긴다면, 멘션 주실 때 어떤 경위를 통해 앱이 죽었는지 말씀해주시면 감사하겠습니다!


또한, 애플리케이션이 죽었을 경우에, 디버깅을 위해 Crashlytics 를 통해 익명으로 버그정보를 수집합니다!


테스트는 TestFlight 를 통해 진행되며, Qubellbook 의 최소 iOS 구동사양은 iOS 9.0 이상입니다.


TestFlight 이용 시, TestFlight 사용자 추가 메일이 1차 발송되고, 앱 승인 메일이 2차 발송되니 신청하실  Apple ID 의 이메일 보관함을 확인해주시면 됩니다.


처음 앱을 로그인했을 때 나오는 팝업에서 반드시 필요한 정보들을 동기화해주세요!

앱이 정상적으로 작동하기 위해 꼭 필요합니다!!


소스개선을 통해 점점 동기화 시간을 단축시키고 있으니, 테스터 유저 분들께 양해를 구합니다..


* 아이패드는 로그인 화면에서 캡챠 인증이 잘려서 나오니 로그인 시 유의해주세요! 아마 노력과 추리가 필요할 수 있습니다.

빨리 수정하겠습니다.


2016.09.07 수정 - 코나미가 더 이상 구글의 캡챠 서비스를 사용하지 않아 잘리는 화면 사라짐


iOS 서열표는 플레이어의 기록에 존재하지 않는 곡은 나타나지 않습니다.

없는 기록을 불러오는데 충돌이 발생하여 그 부분은 현재 ? 처리를 할 수 있도록 준비중입니다.


자세한 문의사항은 트위터 @CenoX_Kang 로 멘션주세요!


2016.06.05 추가 --------------//



기본적인 작동 영상입니다. 참고해주세요!


TestFlight 테스팅에 대해 좀 더 자세한 설명이 필요할 듯 하여 적고가겠습니다.


https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide_ko/Chapters/BetaTestingTheApp.html


위에 기재된 내용 그대로 "TestFlight 베타 테스트를 사용하면 테스터를 대상으로 App의 사전 출시 빌드를 배포하여 피드백을 수집하고 App Store에서의 App 출시를 준비할 수 있습니다."


애플에서 지원하는 베타테스팅 플랫폼이며, 이 테스팅을 위해서는 유저분들의 이메일을 수집합니다.

다만, 다운로드의 편의를 위해서 현재 유저분들이 App Store 의 로그인을 위해 사용하시는 이메일을 등록해주시면, 메일함에서 신청을 확인하시고, App Store 에서 TestFlight 어플리케이션을 받아 테스팅해주시면 됩니다!


테스트가 끝나면, 참여해주셨던 모든 유저분들의 이메일은 삭제됩니다!



2016.06.07 추가 --------------//


TestFlight 테스트 수락 및 앱 다운로드 방법!



먼저 App Store 에서 TestFlight 애플리케이션을 설치합니다.


그리고, Apple ID 로 쓰고 있는 메일의 메일함을 확인합니다.



Start Testing 버튼을 눌러 TestFlight 로 넘어가고, ACCEPT 를 눌러 테스팅을 시작합니다.





이제, 앱을 실행하시고 각 테스터들의 KONAMI ID 로 로그인하여 테스팅을 시작해주시면 됩니다!


업데이트 2016.06070921


추가된 변경사항

 - 첫 동기화는 반드시 필요함에 따라, 취소버튼을 삭제하였습니다.

 - 첫 동기화 중 팅기거나, 사용자가 앱을 종료했을 경우 다음 실행시 동기화 팝업이 다시 나타나도록 수정하였습니다.

 - 첫 로그인 시 플레이어의 엠블럼 이미지의 동기화가 완료되지 않았을 때 메뉴를 호출할 경우 팅김 현상이 발생함을 확인, 기본 정보 동기화 전에는 메뉴 호출 제스처와 버튼이 비활성화 되도록 처리하였습니다


기존 테스트 항목

 - 각 테스터들의 계정을 통해 앱의 전체적인 안정성 평가

 - 오역 등의 번역 문제

 - 플레이어의 음악 기록이 정렬된 뷰에서 조건에 맞게 정렬이 작동하는지 확인

 - iOS 서열표의 정상 작동 확인


2016.06.08 추가 --------------//


업데이트 2016.06081312


추가된 변경사항

 - Play data 탭에 한번도 들어가지 않고 서열표부터 들어갔을 경우에 발생할 수 있는 충돌을 방지하였습니다.

 - 데이터 마이그레이션 부분에서, 카드번호를 가져올 수 없었던 경우에 다른 방법을 시도할 수 있도록 변경하였습니다.

 - 서열표에서의 S 랭크 집계가 불가능 했던 점을 수정하였습니다.


기존 테스트 항복

업데이트 2016.06070944

 - 첫 동기화는 반드시 필요함에 따라, 취소버튼을 삭제하였습니다.

 - 첫 동기화 중 팅기거나, 사용자가 앱을 종료했을 경우 다음 실행시 동기화 팝업이 다시 나타나도록 수정하였습니다.

 - 첫 로그인 시 플레이어의 엠블럼 이미지의 동기화가 완료되지 않았을 때 메뉴를 호출할 경우 팅김 현상이 발생함을 확인, 기본 정보 동기화 전에는 메뉴 호출 제스처와 버튼이 비활성화 되도록 처리하였습니다


기존 테스트 항목

 - 각 테스터들의 계정을 통해 앱의 전체적인 안정성 평가

 - 오역 등의 번역 문제

 - 플레이어의 음악 기록이 정렬된 뷰에서 조건에 맞게 정렬이 작동하는지 확인

 - iOS 서열표의 정상 작동 확인


2016.06.11 추가 --------------//


업데이트 - 2016.06111649


업데이트가 늦어 죄송합니다! 개인적인 사정으로 인해 스케쥴이 많이 밀려버렸네요 ㅠㅠ


추가된 변경사항

 - 서열표에서의 S 랭크 집계가 불가능 했던 점을 수정하였습니다. 기존 업데이트에 반영되지 않았습니다. 죄송합니다.

 - 서열표에서의 공유 기능을 강화하였습니다. 오른쪽 끝의 ‘기타’ 버튼을 눌러 공유할 옵션을 더 설정할 수 있습니다.

 - 서열표의 테이블 날짜를 업데이트 하였습니다.

 - 음악 동기화를 통해 항상 레벨 데이터를 새로고침 하도록 변경하였습니다.


기존 테스트 항목

업데이트 2016.06081312

추가된 변경사항

 - Play data 탭에 한번도 들어가지 않고 서열표부터 들어갔을 경우에 발생할 수 있는 충돌에 경고처리를 하였습니다.

 - 데이터 마이그레이션 부분에서, 카드번호를 가져올 수 없었던 경우에 다른 방법을 시도할 수 있도록 변경하였습니다.

 - 서열표에서의 S 랭크 집계가 불가능 했던 점을 수정하였습니다.

업데이트 2016.06070944

 - 첫 동기화는 반드시 필요함에 따라, 취소버튼을 삭제하였습니다.

 - 첫 동기화 중 팅기거나, 사용자가 앱을 종료했을 경우 다음 실행시 동기화 팝업이 다시 나타나도록 수정하였습니다.

 - 첫 로그인 시 플레이어의 엠블럼 이미지의 동기화가 완료되지 않았을 때 메뉴를 호출할 경우 팅김 현상이 발생함을 확인, 기본 정보 동기화 전에는 메뉴 호출 제스처와 버튼이 비활성화 되도록 처리하였습니다

2016.06061740

 - 각 테스터들의 계정을 통해 앱의 전체적인 안정성 평가

 - 오역 등의 번역 문제

 - 플레이어의 음악 기록이 정렬된 뷰에서 조건에 맞게 정렬이 작동하는지 확인

 - iOS 서열표의 정상 작동 확인


핫픽스 업데이트 - 2016.06111940


핫픽스

 - 아이패드에서 서열표 공유를 누르면 앱이 죽는 문제를 해결합니다


추가된 변경사항

 - 서열표에서의 S 랭크 집계가 불가능 했던 점을 수정하였습니다. 기존 업데이트에 반영되지 않았습니다. 죄송합니다.

 - 서열표에서의 공유 기능을 강화하였습니다. 오른쪽 끝의 ‘기타’ 버튼을 눌러 공유할 옵션을 더 설정할 수 있습니다.

 - 서열표의 테이블 날짜를 업데이트 하였습니다.

 - 음악 동기화를 통해 항상 레벨 데이터를 새로고침 하도록 변경하였습니다.



이번 빌드 이후로, 조만간 큰 작업을 해야할 것 같아 당분간 업데이트는 없을 듯 합니다. 큰 문제가 발생하지 않는 한 앱을 크게 개선시켜 돌아올 예정이오니, 테스터 분들께 양해의 말씀을 드립니다...ㅠㅠ 테스터는 아직 자리가 남아있으니 신청하실 분들은 멘션주시거나 DM 주시면 됩니다!


2016.06.13 추가 --------------//


아무래도 개발중인 어플리케이션이므로 Development 가 맞다고 판단, 또한 shiftstudios 의 프로젝트이기에 글의 분류를 Dev. - shiftstudios 로 옮겼습니다.


2016.07.15 추가 --------------//


업데이트 - 2016.07151500

 - 앱 최소버전을 iOS 9.0 으로 올렸습니다. iOS 8.4를 사용하고 계신 유저여러분들께 정말 죄송합니다

 - UI를 전체적으로 변경

 - 동기화 방식 변경, 동기화 진행 상태를 시각적으로 표시, 속도 비약적으로 향상

 - 랭크 테이블의 추가

 - 레벨테이블의 테두리 다듬기 및 플레이 하지 않은 곡은 어둡게 처리

 - 트위터 API 연동을 통해 메인 UI에서 @jubeat_staff 의 최신 피드를 받아올 수 있음

 - 이미지 관리 개선

 - 뮤직 뷰의 UI 변경, 곡 정렬속도 향상

 - 레코드 뷰 다시 제작


그냥 앱을 새로 짰습니다. 업데이트가 늦은 점 죄송합니다.


뮤직뷰에서 평균 점수를 구하는 기능이 지금은 작동하지 않습니다.

전체적인 UI 갈이로 인해 번역작업의 진행을 마무리하지 못했습니다. 빠른 시일내에 업데이트 하겠습니다.


버그제보는 언제든지 트위터 @CenoX_Kang 으로 부탁드립니다.


이전 업데이트 기록


핫픽스 업데이트 - 2016.06111940


핫픽스

 - 아이패드에서 서열표 공유를 누르면 앱이 죽는 문제를 해결합니다


추가된 변경사항

 - 서열표에서의 S 랭크 집계가 불가능 했던 점을 수정하였습니다. 기존 업데이트에 반영되지 않았습니다. 죄송합니다.

 - 서열표에서의 공유 기능을 강화하였습니다. 오른쪽 끝의 ‘기타’ 버튼을 눌러 공유할 옵션을 더 설정할 수 있습니다.

 - 서열표의 테이블 날짜를 업데이트 하였습니다.

 - 음악 동기화를 통해 항상 레벨 데이터를 새로고침 하도록 변경하였습니다.


업데이트 - 2016.06111649


업데이트가 늦어 죄송합니다! 개인적인 사정으로 인해 스케쥴이 많이 밀려버렸네요 ㅠㅠ


추가된 변경사항

 - 서열표에서의 S 랭크 집계가 불가능 했던 점을 수정하였습니다. 기존 업데이트에 반영되지 않았습니다. 죄송합니다.

 - 서열표에서의 공유 기능을 강화하였습니다. 오른쪽 끝의 ‘기타’ 버튼을 눌러 공유할 옵션을 더 설정할 수 있습니다.

 - 서열표의 테이블 날짜를 업데이트 하였습니다.

 - 음악 동기화를 통해 항상 레벨 데이터를 새로고침 하도록 변경하였습니다.


기존 테스트 항목

업데이트 2016.06081312

추가된 변경사항

 - Play data 탭에 한번도 들어가지 않고 서열표부터 들어갔을 경우에 발생할 수 있는 충돌에 경고처리를 하였습니다.

 - 데이터 마이그레이션 부분에서, 카드번호를 가져올 수 없었던 경우에 다른 방법을 시도할 수 있도록 변경하였습니다.

 - 서열표에서의 S 랭크 집계가 불가능 했던 점을 수정하였습니다.

업데이트 2016.06070944

 - 첫 동기화는 반드시 필요함에 따라, 취소버튼을 삭제하였습니다.

 - 첫 동기화 중 팅기거나, 사용자가 앱을 종료했을 경우 다음 실행시 동기화 팝업이 다시 나타나도록 수정하였습니다.

 - 첫 로그인 시 플레이어의 엠블럼 이미지의 동기화가 완료되지 않았을 때 메뉴를 호출할 경우 팅김 현상이 발생함을 확인, 기본 정보 동기화 전에는 메뉴 호출 제스처와 버튼이 비활성화 되도록 처리하였습니다

2016.06061740

 - 각 테스터들의 계정을 통해 앱의 전체적인 안정성 평가

 - 오역 등의 번역 문제

 - 플레이어의 음악 기록이 정렬된 뷰에서 조건에 맞게 정렬이 작동하는지 확인

 - iOS 서열표의 정상 작동 확인


후우,, 좀 더 빠른 구동 방식을 구상하다가 조금 새로운게 떠올라 앱을 전체적으로 갈아버리는 작업이 되어버렸네요 ㅠㅠ

트위터를 주축으로 SNS 공유기능을 좀 더 활성화 해 보려고 노력했고, 나름의 홍보효과(?)도 있지 않을까- 하고 있어요


그 공유버튼에서 트위터와 페이스북을 추가하시려면, 일단 iOS 기본 설정 내에 트위터 또는 페이스북에 로그인 하신 후, 공유버튼을 눌러 창이 뜨면 에어드롭 밑의 단락의 오른쪽 끝에서 페이스북이나 트위터를 추가해주시면 되요! 

만약 기본으로 설정할 수 있는 방법이 있다면 찾아서 적용해볼게요


사실 카카오도 추가하려 했는데, API가 너무... 그냥 하다 포기했어요


아 그리고 아이패드 로그인 화면은 아직 못고쳤습니다....


그럼 즐거운 리창인생에 도움이 되길 바라며 테스팅 잘 부탁드립니다!!


2016.07.18 추가 --------------//


업데이트 - 2016.07180825


- RANK TABLE 에서 S 랭크의 갯수와 SS 랭크의 갯수가 같게 나오는 문제를 해결합니다.

- MUSIC 에서 이미지가 로딩되지 않을 때 팅기는 문제를 해결합니다.


테스터 분들 중 아무도 팅겼다는 보고가 없어서 놀랬습니다 ㄷㄷ...

왜 나만 이렇게 팅기나 하고 봤더니 신곡이 문제더라구요, 이미지 데이터베이스도 한번 업데이트 해야겠네요ㅠㅠ


업데이트 - 2016.7181420


 - 메인뷰에서 화면이 나오지 않는 문제를 해결 ( 검증되지 않음, 테스트 필요 )

 - 기존 이미지를 다운로드 받는 URL을 수정

 - 기타 버튼 등의 동작 수정


이번 버전부터 Firebase 를 지원합니다.


왜 화면이 안나오는걸까요오..


2016.08.12 추가 --------------//

업데이트 - 2016.08121430


 - 파이어베이스 기반 애드센스 API 추가. ( 테스트 플라이트 업데이트 버전은 광고가 노출되지 않음 )

 - 3D Touch 지원 기종에서 Music 화면과 Level Table 에서 Peek & Pop 지원

 - 3D Touch 지원 기종에서 홈화면 Quick Action 지원

 - 매일 아침 7시마다 리게이들을 위한 푸쉬알림 지원

 - 번역 작업 마무리 중

 - 크레딧 화면의 추가 ( 아직 다 정리되지 않음 , 크레딧 화면 진입 시 기존 메인화면의 인스턴스가 날아가니 주의! )


또 오랫동안 방치해버렸습니다 죄송합니다아...

3D Touch 관련 기능은 8월 7일부터 11일동안 진행했던 Team ArcStar MT 중, 6S 를 사용하고 있는 팀원의 기기를 빌려 재빠르게 개발했습니다

잘 작동했으면 좋겠네요 이젠 테스트도 못하는데...


2016.08.24 추가 --------------//

업데이트 - 2016.08241500


 - 일본어 번역의 완료 ( Thanks to Kanu )

 - 리게이들을 위한 알림이 여러개 중첩되는 오류를 수정

 - 특정 뷰의 레이블이 잘못된 것을 표기하던 오류 수정

 - 특정 HTML 기호에 의한 곡명 표기 오류 수정 (Milchstraße -> Milchstraße)

 - 동기화 시 화면이 꺼지지 않도록 수정

 - 레코드 뷰의 오타를 수정

 - Music 뷰에서 평균점수 계산 추가 ( 레벨과 난이도를 반드시 특정해야 함. 하나라도 ALL 일 경우 10레벨 EXT 평균 계산 )


이제 슬슬 출시해도 될 것 같은 분위기

팅기시면 언제든지 연락주세요! 트위터 @CenoX_Kang 입니다


2016.08.25 추가 --------------//

업데이트 - 2016.08251320


 - 버전 변경으로 인해 재 동기화가 필요할 경우의 알림창 변경

 - 레코드 뷰의 버튼을 지역화함

 - 레코드 뷰의 뒷배경이나 비활성화 된 버튼을 누르면 뷰가 사라지는 것을 비활성화

 - 몇몇 뷰의 크기를 조정

 - 없는 기록을 참조하려는 경우 어플리케이션이 팅기는 문제를 수정


2016.09.07 추가 --------------//


업데이트 - 2016.09070440


 - 메인뷰에 Dig Dig Qubell 메뉴 추가

 - 메인뷰에서 음악데이터 재로딩 시, 이미지 동기화 부분을 제거

 - Dig Dig 큐벨 초안 작업 완료

 - 레벨테이블, 랭크테이블 또는 레코드뷰에서 공유 기능을 통해 사진을 카메라롤에 추가하면 토스트 추가

 - 레코드 뷰 어느곳에서나 화면을 좌 우로 넘기면 난이도를 넘기는 기능 추가


드디어! Dig Dig가 정상적으로 작동합니다 ㅠㅠ!


2016.11.29 추가 --------------//


업데이트 - 2016.11282212


 - 메인 뷰 새로운 디자인 적용 중

 - Play Data 새로운 디자인 적용 중

 - 기록 동기화 속도 비약적으로 향상 ( 23초 ~ 1분 31초 )

 - 레코드 뷰 삭제

 - 뮤직 뷰 디자인 변경


오랜만입니다. 그동안 잘 지내셨나요 :)

Qubellbook 이 Jubeatbook 으로 패키지명을 바꾸고, Discord 를 통해 alpha 챗을 운영을 시작했습니다. (https://discord.gg/rFYRBXu)


2016.12.01 추가 --------------//


업데이트 - 2016.12011132


 - 메인 뷰의 Level Table 임시로 삭제 및 Music 리스트 추가

 - 기존 Music 의 기능이 Records 로 변경

 - 함수 최적화


간단한건 금방 구현되서 정말 좋아요


2016.12.10 추가 --------------//


업데이트 - 2016.12100213

 - Records 의 기본 테이블 변경

 - DigDig 에서 Risky unlock challange 때문에 앱이 죽던 버그 수정

 - Firebase 알림 기능 추가 (TEST)

 - 함수 최적화

 - 기기가 지정된 세로 화면값보다 더 큰 스크린을 가졌을 경우, 기기의 스크린 높이를 사용하도록 수정


분명 소스코드는 엄청 갈아엎였는데 막상 보니 수정사항이 많이 없네요


// 핫픽스 - 2016.12010316

 - Dig Dig 동기화 오류 수정


2016.12.16 추가 --------------//


업데이트 - 2016.12161019

 - 레코드 뷰 기능 추가 ( 점수 추적 그래프(BETA), 가사 미지원 )

 - 기존 기록정보를 미리 불러와, 이전기록과 현재 기록의 차이가 있는 경우 그 차이를 표시하도록 설정.

 - 플레이 데이터 동기화 방식 변경

 - 뷰 로딩 과정 및 앱 검사과정 변경 및 뷰 업데이트 로직 강화

 - 플레이 시간에 따라 기록을 자동으로 부르도록 변경

 - 기존의 마지막 플레이 시간과 동기화된 마지막 플레이 시간이 다르면 유저 데이터를 자동으로 동기화 하도록 변경

 - 메인 뷰에서 다른 메뉴로 진입 시, 길었던 백버튼 타이틀 제거.

 - WebView 에서 구글 리캡챠를 이용한 로그인 사이트 접근 허용

 - 로직이 로드되기 전 새로고침 버튼 비활성화

 - 앱 실행 때 버전 업그레이드로 내부 저장소가 삭제되는 기능 삭제

 - Dig Dig 뷰 로직 변경

 - 뮤직 뷰 버그 수정


2017.01.03 추가 --------------//


업데이트 - 2017.01031626

 - 악곡의 미리 채보를 볼 수 있는 채보뷰어 추가.

 - 데이터 세분화

 - Records 에서 10레벨 뿐만 아니라 모든 난이도에 대한 색 강조표시

 - 악곡 데이터가 없을 때 앱이 죽는 버그 수정

 - 점수 범위에 맞게 점수 차트 범위조정 기능 추가

 - Firebase Crash Report 기능 지원.


바이너리 처리를 잊어 업데이트가 늦어졌습니다. 죄송합니다.

채보뷰어의 동시치기 옵션은 선택 가능입니다만, UI 미구현의 이유로 인해 강제로 On 상태입니다.


2017.01.24 추가 --------------//


업데이트 - 2017.1120226

 - Music, Records 검색기능 추가 ( 아직 완성되진 않음 )

 - 특정 함수가 계속 I/O에 접근하는 것을 방지, 그에따른 소스 변경작업

 - Records 디자인 변경



어쩌면, 오랜만의 개발..관련 포스팅일까요..


갑자기 저번에 있었던 카카오API에 대한.. 아픈기억이… 잠깐.


오늘은 iOS에 내장된 자체적인 Twitter 프레임워크를 이용해서 텍스트뷰에 작성한 문장을, 트위터에 업로드시키는 간단한 어플리케이션입니다.


중요할 것 같은 소스코드엔 주석처리를 해두었고, 메소드를 #pragma mark 로 묶어두었습니다만, 잘 정리를 해둔건지는 저도 의문이네요.


간단히


SLComposeViewController


를 이용해서, UI상의 텍스트뷰에 입력한 문장을 uploadString으로 변수화시키고, 트위터에 글을 올리는 저 SLComposeViewController를 호출, 초기문장을 변수화시킨 uploadString으로 설정하고, 포스트를 눌렀을 때,


설정 - Twitter에 등록시킨 계정에 글을 포스팅하는..


엄청 간단한 어플리케이션이에요..




이번에 SNS 관련해서 뒤적거리다가 알게된김에 간단히.. 샘플 만들어서 공유해봤어요


아, 깃허브로 공유할꺼라서 앱도 현지화 시켜봤구요..ㅋㅋㅋ

덕분에 많이 알았네요


사용은 자유입니다만, 다른곳에 코드를 퍼가거나 하실때에는 원작자를 꼭 밝혀주세요!!!!!


그럼, 좋은하루되세요~!!



스크린샷:












'Dev. > iOS Dev.' 카테고리의 다른 글

kakaoDev Talk. -절망  (0) 2014.12.16
KakaoDev Talk -삽질  (0) 2014.12.16
KakaoDev Talk.  (0) 2014.12.15
iOS 학교정보 파싱 소스코드  (0) 2014.09.08


kakaoDev Talk. -절망


Dev./iOS Dev.

Written by CenoX on 2014. 12. 16. 04:10

으ㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏ


    func something(KOSessionCompletionHandler) -> Void

    {

        if (KOSession.sharedSession().isOpen()) {

            println("Login Success")

            UIApplication.sharedApplication().delegate?.respondsToSelector("ShowMainView")

        } else {

            var alert = UIAlertController(title: "Error", message: errors.localizedDescription, preferredStyle: .Alert)

        }

    }

    

    @IBAction func invokeLoginWithTarget() {

        KOSession.sharedSession().close()

        something(errors)

    }


아. 미치겠네 정말..


위의

    func something(KOSessionCompletionHandler) -> Void

    {

        if (KOSession.sharedSession().isOpen()) {

            println("Login Success")

            UIApplication.sharedApplication().delegate?.respondsToSelector("ShowMainView")

        } else {

            var alert = UIAlertController(title: "Error", message: errors.localizedDescription, preferredStyle: .Alert)

        }

    }

함수는 잘 작동한다.


이 말은 아마도 내가 해석한게 맞다는 의미인 것 같은데


문제는

 @IBAction func invokeLoginWithTarget() {

        KOSession.sharedSession().close()

        something(errors)

    }

이곳이다.


이부분

something(errors)

에서 [ 'NSError is not convertible to 'KOSessionCompletionHandler' ]라는 에러가 출력된다



KOSessionCompletionHandler는 [ @objc_block(NSError!) -> Void ] 라고 정의되어있다


아 헷갈려. 


분명 여기선 인수값을 NSError로 준 것 아니였나?

[[KOSession sharedSession] openWithCompletionHandler:^(NSError *error)



아니면 NSError라는 코드블럭을 하나 생성해서 그것을 KOSessionCompletionHandler()에 집어넣어줘야 한다 그소리인가?



아니아니 뭐라는거야 NSError라는 타입을 가진 코드블럭이라고 해야할까


또 삽질.. 해봐야겠다..


으어ㅓㅓ..정말 같은회사에서 만든 프로그래밍 언어일텐데.. 접목이...으어ㅓ 미친다..


KakaoDev Talk -삽질


Dev./iOS Dev.

Written by CenoX on 2014. 12. 16. 03:56

KOSession.sharedSession().openWithCompletionHandler()


어제 만나 아직도 해결을 못본 이 에러.


Swift상에선 ()안에 들어갈 구문이

completionHandler: KOSessionCompletionHandler!(NSError!) -> Void 타입으로 명시되어 있는데


아마 내 생각엔 NSError라는 변수를 인수로 삼아 Void로 반환하라 는 것 같은데

이 구문을 어떻게 처리해야 할까


기존의 Objective-C 로 작성된 코드


[[KOSession sharedSession] openWithCompletionHandler:^(NSError *error)


이 구문에서 처리방식은


openWithCompletionHandler:^(NSError *error)completionHandler라고 명시되어 있다.



이 두개를 기반으로 기존 Objective-C 코드와 Swift 코드를 비교하면


openWithCompletionHandler:^(NSError *error)completionHandler == KOSessionCompletionHandler!(NSError!) -> Void 라는 말이 된다.


이 두개롤 다시 놓고 본다면

^(NSError *error)에서 ^는 다른 언어에서 클로저와 비슷한 개념이라고들 하고 (http://stackoverflow.com/questions/3499186/what-does-this-caret-syntax-with-void-on-either-side-mean) [NSError *error] 라는 코드블럭인것같은데


아니 잠깐만, 어.. 음.. 뭔가 감이 오다 마는것 같은 느낌이 강한데..


만약 저 안에 들어가는 구문이, ^(NSError *error)라는 인수를 이용해 그 아래 있는 { * }의 코드를 수행하고, Void를 리턴하는 방식이라면 (아 지금 내가 뭘 씨부리는거야)


그럼 만약 스위프트로 나타낸다면 인수를 이용해 반환값을 리턴하는


    func something(KOSessionCompletionHandler) -> Void

    {

        

    }


이런 개념일려나?

음.. 뭐랄까 정말 헷갈린다


만약 이런 방식이라면, 굳이 

KOSession.sharedSession().openWithCompletionHandler()

라는 방식을 이용하지 않고

저 함수위에 적용한 다음, 바로 something() 이런식으로 호출해버리면 그만 아닌가?


어.. 지금 당장 해봐야겠다


KakaoDev Talk.


Dev./iOS Dev.

Written by CenoX on 2014. 12. 15. 05:02

질문에 관한 내용은 카카오스토리 API이고, 플랫폼은 iOS SDK 8.1, 언어는 Swift입니다.


Swift가 나오고, 애플이 Swift와 Objective-C를 둘 다 사용할 수 있도록 해준 덕분에 현재 MyApp-Bridging-Header.h 파일에 


//

//  Use this file to import your target's public headers that you would like to expose to Swift.

//



#import <KakaoOpenSDK/KakaoOpenSDK.h>

이렇게 올려놓고 쓰고 ViewController.swift 파일에서 호출해서 쓰고있습니다.


그럼.. 염치 불구하고 질문 올리겠습니다..


아래에 있는 자료가 원래 KakaoDevelopers_ (https://developers.kakao.com/) 에 업로드 되어있는 Objective-C로 작성 된 기존 KakaoStorySampleLoginViewController.m 파일입니다.


/**

* Copyright 2014 Daum Kakao Corp.

*

* Redistribution and modification in source or binary forms are not permitted without specific prior written permission.

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*    http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/


#import "KakaoStorySampleAppDelegate.h"

#import "KakaoStorySampleLoginViewController.h"


#import <KakaoOpenSDK/KakaoOpenSDK.h>


@implementation KakaoStorySampleLoginViewController


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

    if (self) {

        self.title = @"Login";

    }

    return self;

}


- (void)loadView {

    [super loadView];


    // logo display

    int marginBottom = 25;


    UIImage *kakaoLogoImage = [KOImages kakaoLogo];

    UIImageView *kakaoLogoImageView = [[UIImageView alloc] initWithImage:kakaoLogoImage];

    kakaoLogoImageView.frame = CGRectMake((self.view.frame.size.width - kakaoLogoImage.size.width) / 2, (self.view.frame.size.height - kakaoLogoImage.size.width - marginBottom) / 2, kakaoLogoImage.size.width, kakaoLogoImage.size.height);

    kakaoLogoImageView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;


    [self.view addSubview:kakaoLogoImageView];


    // button display

    UIButton *kakaoAccountConnectButton = [self createKakaoAccountConnectButton];

    [self.view addSubview:kakaoAccountConnectButton];


}


- (UIButton *)createKakaoAccountConnectButton {

    // button position

    int xMargin = 30;

    int marginBottom = 25;

    CGFloat btnWidth = self.view.frame.size.width - xMargin * 2;

    int btnHeight = 42;


    UIButton *btnKakaoLogin

            = [[KOLoginButton alloc] initWithFrame:CGRectMake(xMargin, self.view.frame.size.height - btnHeight - marginBottom, btnWidth, btnHeight)];

    btnKakaoLogin.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;



    // action

    [btnKakaoLogin addTarget:self action:@selector(invokeLoginWithTarget:) forControlEvents:UIControlEventTouchUpInside];


    return btnKakaoLogin;

}


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view from its nib.

}


- (void)viewDidUnload {

    [super viewDidUnload];

    // Release any retained subviews of the main view.

    // e.g. self.myOutlet = nil;

}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {

        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);

    } else {

        return YES;

    }

}


#pragma mark - actions


- (IBAction)invokeLoginWithTarget:(id)sender {

    [[KOSession sharedSession] close];


    [[KOSession sharedSession] openWithCompletionHandler:^(NSError *error) {


        if ([[KOSession sharedSession] isOpen]) {

            // login success.

            NSLog(@"login success.");

            [[[UIApplication sharedApplication] delegate] performSelector:@selector(showMainView)];


        } else {

            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"에러"

                                                                message:error.localizedDescription

                                                               delegate:nil

                                                      cancelButtonTitle:@"확인"

                                                      otherButtonTitles:nil];

            [alertView show];

        }


    }];

}


- (IBAction)invokeCancelLoginWithTarget:(id)sender {

    [[KOSession sharedSession] close];

}


- (IBAction)invokeToggleStatusBar:(id)sender {

    [[UIApplication sharedApplication] setStatusBarHidden:![UIApplication sharedApplication].statusBarHidden withAnimation:YES];

}


@end




그리고 아래가 지금 제가 만들고 있는 Swift 파일입니다.

//

//  ViewController.swift

//  ManyPost

//

//  Created by CenoX on 2014. 12. 15..

//  Copyright (c) 2014 CenoX. All rights reserved.

//


import UIKit



class ViewController: UIViewController {


    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

        

    }


    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }

    

    /*==========================================*/

    /*========Starting Make View for Kakao API =======*/

    /*==========================================*/

    

    override func loadView() {

        super.loadView()

        

        var marginBottom: CGFloat

        marginBottom = 25

        

        var kakaoLogoImage: UIImage!

        kakaoLogoImage = KOImages.kakaoLogo()

        

        var kakaoLogoImageView: UIImageView!

        kakaoLogoImageView.image = kakaoLogoImage

        

        kakaoLogoImageView.frame = CGRectMake((self.view.frame.size.width - kakaoLogoImage.size.width) / 2, (self.view.frame.size.height - kakaoLogoImage.size.width - marginBottom) / 2, kakaoLogoImage.size.width, kakaoLogoImage.size.height)

        

        kakaoLogoImageView.autoresizingMask = UIViewAutoresizing.FlexibleLeftMargin | UIViewAutoresizing.FlexibleRightMargin | UIViewAutoresizing.FlexibleTopMargin | UIViewAutoresizing.FlexibleBottomMargin

        

        self.view.addSubview(kakaoLogoImageView)

        

        var kakaoAccountConnectButton: UIButton!

        kakaoAccountConnectButton.addTarget(self, action: "createKakaoAccountConnectButton", forControlEvents: .TouchUpInside)

        /*

        /*Break Point*/

        Original Source (Objective-C)

        

        /*==========================================*/

        UIButton *kakaoAccountConnectButton = [self createKakaoAccountConnectButton];

        /*==========================================*/

        */

    }

    

    func createKakaoAccountConnectButton()

        //Action for kakaoAccountConnectButton

    {

        var xMargin:CGFloat = 30

        var marginBottom: CGFloat = 25

        var btnWidth: CGFloat = self.view.frame.size.width - xMargin * 2

        var btnHeight: CGFloat = 42

        

        var btnKakaoLogin: UIButton!

        btnKakaoLogin.frame = CGRectMake(xMargin, self.view.frame.size.height - btnHeight - marginBottom, btnWidth, btnHeight)

        btnKakaoLogin.autoresizingMask = UIViewAutoresizing.FlexibleTopMargin | UIViewAutoresizing.FlexibleBottomMargin

        

        btnKakaoLogin.addTarget(self, action: "invokeLoginWithTarget", forControlEvents: .TouchUpInside)

    }

    

    /*==========================================*/

    /*============#pragma mark - actions===========*/

    /*==========================================*/

    

    @IBAction func invokeLoginWithTarget() {

        var errors: NSError

        KOSession.sharedSession().close()

        KOSession.sharedSession().openWithCompletionHandler(errors) {

            if (KOSession.sharedSession().isOpen()) {

                println("Login Success")

                UIApplication.sharedApplication().delegate?.respondsToSelector("ShowMainView")

            } else {

                var alert = UIAlertController(title: "Error", message: errors.localizedDescription, preferredStyle: .Alert)

            }

        }

    }

}



이렇게 적었습니다만 강조하고 싶은 부분은 두부분 입니다.

일단 첫번째

var errors: NSError

KOSession.sharedSession().openWithCompletionHandler(errors) {



기존 소스코드는

[[KOSession sharedSession] openWithCompletionHandler:^(NSError *error) {

라고 처리가 되어 있습니다만, Swift상에서 *Handler:^(NSError *error) 부분을 어떻게 처리해야 할 지 모르겠습니다..



직접 선언 된 헤더파일을 살펴보면

/*!

 기기의 로그인 수행 가능한 카카오 앱에 로그인 요청을 전달한다.

 @param completionHandler 요청 완료시 실행될 block. 오류 처리와 로그인 완료 작업을 수행한다.

 */

- (void)openWithCompletionHandler:(KOSessionCompletionHandler)completionHandler;

라고 적혀 있고, 스위프트에서 구문을 호출 할 때 *CompletionHandler를 어떻게 처리해야할 지에 대한 설명도 간략히 나와있습니다만


아무리 고심해도 이 부분을 어떻게 처리해야 할지 모르겠습니다..

도와주세요..ㅠ


두번째는

UIApplication.sharedApplication().delegate?.respondsToSelector("ShowMainView")

입니다.


기존 소스코드를 보면

[[[UIApplication sharedApplication] delegate] performSelector:@selector(showMainView)];


이렇게 처리가 되어 있습니다만


NSObject안에 속해있는 -performSelector: 구문은 swift에서는 사용할 수 없습니다..ㅠ ( http://stackoverflow.com/questions/24158427/alternative-to-performselector-in-swift )


사용 가능하지 않다는 말에, 자포자기 하며 사용할 만한 소스코드를 찾아서 적은 코드가 바로 저


UIApplication.sharedApplication().delegate?.respondsToSelector("ShowMainView")


입니다만, 작동 할 것 같진 않아보입니다.


iOS 학교정보 파싱 소스코드


Dev./iOS Dev.

Written by CenoX on 2014. 9. 8. 20:21

iOS 학교정보 파싱 소스코드




안녕하세요 민족 대명절 추석이라는데 정말 신명나게 할짓이 없는 CenoX 입니다


청소년 개발자시라면 분명 자신의 '학교앱' 이라는 것에 대해 관심을 가지실텐데요, 


'자기 학교는 어플리케이션도 개발할 수 있는 멋진 학교다' 라던가

'내가 학교 어플리케이션을 만들면 학교에서 유명해지겠지' 라던가


뭐 다양한 이유가 있을거라 생각합니다




 주변에 보면 김급식이나 장급식 같은 여러 급식 정보 어플리케이션을 볼 수 있는데  그 어플리케이션들은 어떻게 당신이 학교정보만 입력했는데도 학교정보를 찾아오는지.. 궁금하지 않나요?


전 그부분이 궁금해서 이 '학교앱' 이라는 걸 개발해보기 시작했습니다


본문에 앞서 Wier의 김규한 팀장님께 감사의 말씀드립니다

많은도움 주셨습니다



일단 차례차례 목표를 잡아보죠


먼저



학교정보를 로딩 후 저장해야하고,

그 학교정보를 토대로 급식정보 불러온다.



이게 대략적인 어플리케이션의 핵심 기능이 되겠죠?

더 이상의 기능을 넣는것은 개발자들 마음대로 하는거니까요 :)




[소스 설명]

소스가 돌아가는 방식은 꽤나 간단합니다

Picker View에서 자신이 다니는 학교의 교육청을 불러온 후, 자신의 학교를 검색하면

교육청의 주소에서 해당값의 학교를 찾아 반환되는 값을 파싱, 필요한 정보만 걸러내는 방식입니다


*왜 굳이 교육청을 구분해야 하느냐에 대해서

학교이름에는 중복이 되는학교가 있는데다가, 각 교육청마다 사이트가 다릅니다

(서울특별시교육청주소: http://hes.sen.go.kr/, 경기도교육청주소: http://hes.sje.go.kr/)


PickerView의 row들은 education.plist에서 불러옵니다


그럼, 필요하다고 생각되는 정보는 3개

NSString *namResult;

NSString *schResult;

NSString *codResult;


먼저 말씀드리자면 namResult는 학교의 이름값을 반환하고,

schResult는 학교의 위치, 마지막으로 codResult는 학교 고유코드입니다


또 하나의 NSString변수 eachURL은 PickerView가 움직일때마다 실행되는

-(void)pickerView: didSelectRow: inComponent 메서드에서 각 교육청에 해당되는 URL이 변수값으로 설정됩니다


검색어들이 문자열조합을 거쳐서 나갈때는

stringByAddingEscapesUsingEncoding: 메소드를 거쳐 UTF8로 인코딩 되어 값을 내보내고, 반환받은 값은 파싱과정을 거쳐 걸러진 후, 인코딩 되지 않은 상태로 저장됩니다 (인코딩이 되지 않았더라도, 자체적인 코드 스칼라를 통해 출력시 한글로 정상출력됩니다)



모든 값들을 불러오고, 정상적으로 수행하였다면, schoolInfo.plist 라는 파일을 메인 Bundle에서 가져와 Document 폴더에 복사하고, 거기에 각 변수들을 저장합니다


*주의사항

시뮬레이터에선 메인번들에 schoolInfo.plist가 없어도 정상작동 하지만 기기에서는 오류가 발생하며 튕깁니다. 되도록이면 Supporting Files 그룹 안에 schoolInfo.plist 파일을 생성해주시기 바랍니다 안하면 copy에러나요 ㅇㅇ...



*추가해야할 아울렛

UIPickerView

UIButton *2ea

UITextField

UITextView

UITextField



[파싱방법]


파싱이라고 하긴 좀 뭐한감이 있지만, 뭐 그대로 적어봅니다


왜 파싱이라고 하긴 좀 뭐한감이 있냐면,


parser를 쓰지않아서 파싱이라 하기 뭐하다..랄까 뭐 파싱이라면 파싱이겠지요


소스코드를 보면 중간에 


NSString *nam1 = [NSString stringWithFormat:nam0[2]];

NSArray *nam2 = [nam1 componentsSeparatedByString:@"\""];

namResult = [NSString stringWithFormat:nam2[2]];

NSString *sch1 = [NSString stringWithFormat:sch0[2]];

NSArray *sch2 = [sch1 componentsSeparatedByString:@"\""];

schResult = [NSString stringWithFormat:sch2[2]];

NSString *cod1 = [NSString stringWithFormat:cod0[2]];

NSArray *cod2 = [cod1 componentsSeparatedByString:@"\""];

codResult = [NSString stringWithFormat:cod2[2]];


이런 구문을 중간에 찾으실 수 있을텐데요

간단히 설명드리자면 엄청 간단합니다


위에서 eachURL와 searchID를 조합하여 만든 searchResult.

이 searchResult를 인터넷으로 접속하여보면, 구분하지 않고선 의미없는 텍스트들이 나열이됩니다


그 텍스트들을 NSData로 데이터화하여 plist에 [(NSData *) writeToFile:(NSString *) acomically:(BOOL *)]; 을 통해 저장시키고


아까 정의해두었던 nam, sch, cod의 Result값을 찾아내기 위해 먼저 NSArray를 생성합니다 단, 배열안에 들어가는 원소를 '분리' 하도록 했는데요, 그게 componentsSeparatedByString:(NSString *)에 들어간 각각의 값들입니다


(이부분부터는 김규한 위어팀장님으로 부터 알게된 사실입니다, 감사합니다)


그렇게 때어낸 각각의 배열 3개를 잘 들여다보면 배열의 3번째 원소에


ex) nam0(2) //배열의 원소는 0부터 센다


필요한값이 앞으로 빠진걸 볼 수 있죠


하지만 아까와같이 우리에게 필요한 값은 들어있지만, 좀 더 범위가 작은, 그리고 알아보기 쉬운 배열로 바뀝니다

하지만 우린 '필요한 값' 만 걸러내어야하죠


그래서 또 자르기 위해 배열을 생성하고 원소를 "로 구분하여 분리시킵니다


그리고나서 또 3번째 원소를 살펴보면 우리가 원하는 '값' 만이 존재합니다

그래서 각각의 result를 2번째로 생성한 Array의 3번째 원소로 접근시켜주면 우리가 원하는 값만을 뜯어낼 수 있는거죠


namResult, schResult, codResult 모두 같은 방법으로 분리됩니다




[참고사항]

각각의 IBOutlet들은 용도에 맞게 정의하였으며, 필요하면 바꾸시고, 그냥 쓰셔도됩니다.


IBAction에서의 메소드를 줄이고자, 왠만하면 void구문안에 구현하고 [self (void구문명) ] 식으로 호출할 수 있게 해놓았구요




정보를 plist로 저장하고 이용한 이유는 plist는 어느 뷰에서나 코드만 있으면 접근가능하고, objectForKey만 있으면 사용이 매우 간편하기 때문에 이용했습니다


주석처리 나름 한다곤 했지만 소스정리를 완벽하게 하지 못했을 수도 있으니 궁금한게 있으시면 언제든지 코멘트 날려주세요


개발자를 배려한다면 소스제공자는 써주시는게..ㅎ



[수정사항] - 2014.09.25

기존 소스인

NSString *nam1 = [NSString stringWithFormat:nam0[2]];

    NSLog(@"nam1 is %@", nam1);

    NSArray *nam2 = [nam1 componentsSeparatedByString:@"\""];

    NSLog(@"nam2 is %@", nam2);

    namResult = [NSString stringWithFormat:nam2[2]];

    NSLog(@"namResult is %@", namResult);


에서


[NSString stringWithFormat:nam0[2]] <- 구문에서 Format string is not a string literral (potentially insecure) 경고를 없애기 위하여


//    NSString *nam1 = [NSString stringWithFormat:nam0[2]];

    NSString *nam1 = nam0[2];

    NSLog(@"nam1 is %@", nam1);

    NSArray *nam2 = [nam1 componentsSeparatedByString:@"\""];

    NSLog(@"nam2 is %@", nam2);

//    namResult = [NSString stringWithFormat:nam2[2]];

    namResult = nam2[2];

    NSLog(@"namResult is %@", namResult);


로 교체함.




[첨부파일]


SchoolInfoParser.zip



사진도 올립니다

소스코드 정상작동하는 것 확인했습니다






'Dev. > iOS Dev.' 카테고리의 다른 글

iOS에 내장된 Framework를 이용하여, 트위터에 글 포스팅하는 소스코드.  (0) 2015.02.13
kakaoDev Talk. -절망  (0) 2014.12.16
KakaoDev Talk -삽질  (0) 2014.12.16
KakaoDev Talk.  (0) 2014.12.15