iOS 앱을 만들다 보면 가장 처음 접하게 되는 문제가 이 키보드 가림 문제이다. 보통 책이나 웹상에 떠도는 소스들을 보다보면 매우 간단하게 UITextFiled 하나만 배치하여 키보드가 나타나면 뷰를 올려주고 키보드가 내려가면 다시 뷰를 내려주는 단순한 상황만 언급할 뿐 실제 현업에서 발생 가능한 UITextField가 여러개일 때 즉 상단에 위치한 UITextField컨트롤은 키보드가 보여줘도 그대로 놔둬야 하고 하단에 위치한 UITextField 컨트롤은 키보드만큼 올려줘야 하는 상황에 대해 제대로 해결책을 제시하는 글은 찾기 힘들다. 오늘 소개할 이 방법 말고도 여러 방법들이 있겠지만 초보자도 쉽게 따라할 수 있는 방법을 택하여 소개하고자 한다.
대략 순서는 이러하다. 1. viewDidLoad에서 UITextField Delegate 연결 2. viewDidLoad에서 NotificationCenter를 이용하여 Observer 등록 : 키보드 Show, Hide 이벤트 확인 3. UITextField가 키보드에 가려졌는지 확인을 위한 해당 컨트롤의 위치좌표(Y) 확인 4. 가려졌다면 뷰 이동 O, 안가려졌다면 뷰 이동 X 5. 모든 작업 종료 후 viewWillDisappear에서 2번에서 등록했던 Observer 제거
입력 전 화면첫번째 컨트롤에 포커스 된 화면(키보드가 가려지지 않으므로 뷰 이동 X)두번째 컨트롤에 포커스 된 화면(키보드가 가려졌으므로 뷰 이동 O)세번째 컨트롤에 포커스 된 화면(키보드가 내려간 상태였다면 뷰 이동이 되어야 하지만 이미 키보드가 올라온 상태이므로 뷰 이동 X)
1. TextField의 처리를 위해 UITextFieldDelegate 프로토콜 추가 (이후 TextField 컨트롤은 편의상 컨트롤이라 칭함) class MyViewController: UIViewController, UITextFieldDelegate { }
4. 키보드가 올라왔나 내려갔나 확인을 위해 NotificationCenter로 Observer 등록NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) 이렇게 구현하면 keyboardWillShow, Hide가 없다고 에러가 뜰텐데 원칙상 선 구현 후 정의를 내려야 하지만 편의상 그냥 구현한다.
5. 키보드가 올라왔을 때 컨트롤이 키보드에 가려졌을 때 뷰를 그만큼 올려주는 처리와 내려갔을 때 뷰의 위치를 다시 되돌려 놓는 처리 그리고 지금 컨트롤이 키보드에 가려졌는지 안가려졌는지 확인을 위한 처리 구현
먼저 키보드가 컨트롤을 가렸는지 확인을 위해 변수 하나를 실수형으로 선언한다. varfCurTextfieldBottom: CGFloat = 0.0
현재 포커싱된 컨트롤의 좌표를 구하기 위해 textFieldDidBeginEditing에서 현재 컨트롤의 y좌표와 해당 컨트롤의 높이를 더하면 나중에 키보드에 의해 가려졌는지 확인이 가능하므로 계산 후 일단 보관해둔다. func textFieldDidBeginEditing(_ textField: UITextField) { fCurTextfieldBottom = textField.frame.origin.y + textField.frame.height }
이제 4번에서 등록한 selector함수인 키보드가 나타났을 때와 내려갔을 때 함수를 구현한다. 키보드의 사이즈(구조체)를 keyboardSize에 보관 후 현재뷰의 높이에서 빼주면 키보드가 잡아먹는 정확한 위치를 알 수 있다. 이를 앞서 계산해 보관해둔 fCurTextfieldBottom와 비교하여 fCurTextfieldBottom가 작거나 같으면 가려지지 않았으니 무시하고 크다면 1px이라도 가려졌으므로 현재 뷰를 키보드가 잡아먹는 높이만큼 올려주면 된다. @objcfunckeyboardWillShow(notification: NSNotification) { iflet keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue { iffCurTextfieldBottom<=self.view.frame.height- keyboardSize.height { return } ifself.view.frame.origin.y==0 { self.view.frame.origin.y-= keyboardSize.height } } }
키보드가 사라졌을 땐 간단하다. 그냥 뷰가 이동됐으면 다시 원상복구해주고 아니면 아무런 처리를 하지 않는다. @objcfunckeyboardWillHide(notification: NSNotification) { ifself.view.frame.origin.y!=0 { self.view.frame.origin.y = 0 } }
이렇게만 해두면 기본적인 처리는 다 되었고 만약 완료버튼(done) 대신 뷰의 아무곳이나 터치했을 때 키보드가 내려가길 원한다면 viewDidLoad에 제스쳐를 등록 후 self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(endEditing)))
관련 함수를 구현해주면 깔끔하게 처리가 가능하겠다. @objcfuncendEditing() { txtTmp.resignFirstResponder() txtId.resignFirstResponder() txtPw.resignFirstResponder() }
그럼 sudo 권한을 위해 아이맥 비밀번호를 물어보고 이를 입력하면 한참을 다운로드에서 머물다 설치가 마무리 된다. 대략 20분 이상 걸린것 같다.(회사라 느린것인지 모름)
Terminal Homebrew 설치화면
Homebrew가 설치 되었다면 이제 node를 설치한다. 터미널에서 brew install node 를 입력하고 엔터
node 설치화면
npm이 설치되었으니 이제 본격적인 vue cli 설치를 진행한다. 터미널에서 npm install -g @vue/cli 를 입력하고 엔터 (CLI란 뷰 프로젝트를 빠르게 개발하고 빌드하고 서비스를 런칭시켜주는 틀)
다른 설치파일들과 달리 1~2분 이내로 금방 설치가 완료 된다.
vue 설치 완료 화면
기본 설치까지 모두 완료 되었으므로 이제 실제 vue 프로젝트를 생성해보도록 한다. 프로젝트 생성방법은 터미널에서 vue create 폴더명이므로 vue create test 입력 후 엔터
참고로 화살표키로 다른 기본 설치와 매뉴얼 설치를 선택할 수 있다.
기본 옵션설치이므로 default에서 엔터 설치
default 그대로 설치 진행 중 화면
프로젝트 설치가 완료되면 아래와 같이 생성된 프로젝트를 실행해 볼 수 있도록 친절히 안내가 나온다. (node.js를 경험해봤다면 익숙한 방식이다.)
🎉Successfully created project test. 👉Get started with the following commands: $ cd test $ npm run serve
실제 ls 명령어를 통해 폴더를 확인해보면 test란 폴더가 생성되어 있고
우측 끝에 test란 폴더가 보임
cd 명령어를 통해 이동해보면 아래와 같은 구조로 프로젝트가 생성되어 있음을 알 수 있다. test src App.vue assets components main.js
생성된 프로젝트를 실행하고 실제 브라우저에서 접속해보도록 한다. 먼저 프로젝트 폴더로 이동하기 위해 터미널에서 $cd test 입력 후 엔터
그리고 npm을 통해 프로젝트를 실행하기 위해 터미널에서 $npm run serve 입력 후 엔터를 치면 정상설치가 되었을 경우 아래처럼 친절하게 접속 가능한 주소를 알려준다.
App running at: - Local: http://localhost:8080/ - Network: http://000.000.000.000:8080/ Note that the development build is not optimized. To create a production build, run npm run build.
아무 브라우저나 열고 위 주소를 입력해보자
test로 생성해본 프로젝트 웹 접속 화면
여기까지 간단하게 처음 npm 설치부터 vue 테스트 프로젝트 설치 및 접속까지 알아보았다.
모 PG사의 파라메터들 중 한글을 포함한 파라메터를 넘길 때 UTF-8인 경우 encodeURIComponent를 호출하여 보내야만 했다. 웃긴건 이 PC사 모듈이 PC용이 있고 Mobile용이 있는데 PC용은 encode를 했다가 또다시 decode를 하는 코메디 상황을 연출한다란 점이다. 모바일은 더 웃긴게 encode만 한 후 결제 처리하는 페이지에서 다시 decode를 해야 한다란 점 -_- 도대체 왜 이딴식으로 개발하는지 PG사들 모듈들 보면 다년간 사람손을 많이 타와서 그런지 도무지 이해가 안가는 점이 한두개가 아니다. 왜들 그렇게 모듈을 만들 때 제대로 만들지 못하는건지 그나마 이 PG사는 일전에 망한 큰~기업 PG사에 비하면 양반이다. 그 큰 기업은 참.. 뭘 만들어도 이상한 결과물을 재생산해내는 노하우를 보유한 기업이니 이상하지 않지만 말이다.
javascript의 encodeURIComponent와 decodeURIComponent를 classic asp에서 호출할 때 runat server로 javascript함수를 호출해주면 된다.
<script language="javascript" runat="server"> function decodeUTF8(str) { return decodeURIComponent(str); }
function encodeUTF8(str) { return encodeURIComponent(str); } </script>
새벽에 일어나보니 찬물이 안나온다. ㅎㅎㅎㅎ 이 아파트도 그랬고 지난번에 살던 아파트도 그랬던지라 뭐 당혹스럽거나 그렇진 않고 짜증만 좀 난다.
서울시에서 배포한 수도 동파 방지 비닐 이런거 해봤자 오늘같은 날씨엔 답 안나온다. 복도식 구축 아파트 사는 현실 ㅜㅜ 돈이 원수다. 동파가 10,20년 된 일도 아니거늘 애시당초 이런식으로밖에 건축 설계를 해버린 인간들 잘못이겠지만 -_-
동파방지 비닐을 뜯어보니 고작 이렇게 해놓고 덮어버렸나보다. 이러니 바로 얼어버렸지 이건 동파방지 한것도 안한것도 아니여
냉수만 안나오기 때문에 먼저 냉수 계량기가 어떤건지부터 확인해야했다. 윗계량기가 냉수일까 아랫계량기가 냉수일까 윗 수도 계량기를 열고 얼어버린 수도관을 만져보았다. "싸늘하다. 가슴에 비수가 날아와 꽂힌다." 그렇다. 내가 사는 아파트는 윗 계량함이 냉수 계량함이었다.
이제부터 본격적인 10분안에 동파 수도 계량기 미션 스타트
방법은 간단하다. 미지근한 물보다 조금 더 뜨거운 물을 비닐에 붓고 혹시 모를 참사를 대비해 3중으로 재포장한다. 여기서 포인트는 비닐 봉다리 크기다. 욕심부리지 말고 계량기 사이즈 만큼 만들어야한다. 난 처음에 너무 커서 안들어가길래 주먹 두개 정도 크기로 만들었더니 쏙 들어갔다. 누구는 작게 여러개 넣어야 한다는데 대충 넣음 계량기 안에서 알아서 얼은 계량기를 녹여줄것이다.
SELECT시 특정 필드를 CONVERT할 경우가 종종있다. 그런데 데이터 이상으로 해당 레코드들만 제외하고 CONVERT를 해야 할 경우 WHERE 조건을 준다한들 예외 오류가 발생하게 된다.
예를들어 퇴사일이 없는 (NULL값)직원이 있고 있는 직원이 있다치자 일괄적으로 CONVERT를 실행할 경우 여지없이 해당 NULL값인 직원의 데이터 때문에 예외 오류가 발생한다. 그러하다면 WHERE조건을 주고 해당 레코드들을 제외시킨 후 CONVERT를 하면 되겠거니 싶지만 여지없이 예외오류를 내뱉는다. 서브쿼리로 해당 테이블을 1차 가공 후 CONVERT를 실행시켜도 똑같다.
괴이한건 이 상황에서 그냥 TOP 1000000 을 주고 실행하면 오류를 발생시키지 않는다. 그렇다고 매번 TOP으로 실행하자니 못마땅하다.
이때 사용할 함수가 try_cast, try_convert, try_parse 되시겠다.
조금 더 구체적인 예로 try_convert 함수를 설명해 보겠다.
학생테이블인 STUDENT라는 테이블의 USERID 필드가 VARCHAR(50) 형태로 존재하고 아래처럼 해당 필드는 학번값을 저장하고 있다 치자
USERID
9201013
9201014
crazymyid94
student1101
0088341
0101003
그런데 특이하게 몇몇 레코드만 영문자로 되어 있는 상태고 학번의 앞자리 2자리를 기준으로 입학년도를 추출해야 할 상황인 경우 그냥 CONVERT쿼리를 실행하든 앞서 설명한 상황처럼 SUBQUERY, NOT IN, 알파벳을 제외하는 방법(not like '%[a-zA-Z]%') 등등 뭔짓을 해도 예외오류를 발생시킬 것이다.
메시지 245, 수준 16, 상태 1, 줄 15 varchar 값 'cr'을(를) 데이터 형식 int(으)로 변환하지 못했습니다.