[Spring Boot] 에러해결 : Invalid bound statement (not found)


 - Project.다원의 Ensemble 개발을 진행하면서 나온 문제입니다.

 

사실 어제 삼성의 언팩 행사 틀어놓고 Ensemble 개발을 진행했었는데,

블로그에 글이 안올라온 이유가 딱히 보여드릴만한게 없어서(...) 그랬습니다.. (-_-)...

에러 하나가지고 어제 오늘 잡아먹어버렸네요;; 

 

이번시간에는 해당 에러에 대한 삽질을 하며 결국 어떻게 해당 에러를 해결했는지를 적어볼까합니다.

 


 

해결을 하고보니 진짜 별 문제 아닌데 왜 이리 오래걸렸는지.. (항상 그렇죠 뭐.. 삽질 엄청하다가 해결하면 어.... 아..... 하는.. 그런거 ㅋㅋㅋ - 많은 개발자분들이 공감하지 않을까 싶네요.)

DB연동은 예~~~전에 다끝내놨는데 이제와서 Invalid bound statement (not found): ~~~ 에러가 뜨길래 뭐지? 왜 못찾지? 어디가 문제지? 하면서 열심히 찾아다녔습니다.

 

하지만 열심히 찾아봐도 뭐가 문제인지 모르겠다는 것... (결국 찾아서 해결은 했지만.)

 

원인

저의 경우 DB 연동이랑은 다 문제없이 잘 되었는데, 결국 찾은 문제는 Mapper의 xml단의 id와 interface단의 function명이 달라 생긴 문제였습니다.

당시 function명을 'getAllCode' (공통코드단에서 모든 코드를 가져오는 함수)로 해두었는데 id는 'getAllCodes'로 한 것. (ㅡ..ㅡ 지금 생각해도 s하나 못본거 때문에 삽질한걸 생각하면..)

 

 

해결

function명을 바꾸긴 귀찮아서 (이미 다른쪽에는 다 선언해서 사용중이었..) xml단의 id를 'getAllCode'로 interface와 통일해줌으로써 해결했습니다.

 


눈이 나빠져서 그런가.. (사실 안경써야하는데, 안경이 오래되어 뿌옇게 보여가지고 안쓰게되요. 아.. 안경(블루라이트 차단, 도수있는)값 너무 비쌉니다.ㅠㅠ)

그거 하나를 못 찾아서 몇 시간을 날려먹었네요.

어제 이거 해결하고 자겠다고 새벽 3시쯤 잤는데..

오늘은 시작한지 한시간(...?)걸려 해결했습니다. (하하..)

어찌되었든 끙끙거리다 해결은 되었으니, 또 다음 스탭으로의 개발로 나아갈 수 있을 것 같네요.

 

 

버전정보 (v1.0)

 - v1.0 2020.08.06 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com




[jQuery] $(document).ready() 와 $(window).on("load")


오늘도 어김없이 Project.다원 Ensemble 개발을 진행했지만.. Back단 작업하느라 딱히 보여줄만한게 없어서(눈으로 보이는 부분은 아니기 때문에..ㅠㅠ) 그냥 정리나 해볼까 해서 만들어봤습니다. (...)

 

우리는 jQuery를 사용하다보면 자주 $(document).ready()와 $(window).on("load") 함수를 이용해 front단에서 화면의 시작시 보여줌과 동시에 무언가의 작업을 실행시켜야하는 경우가 있습니다.

오늘은 자주사용하면서 잘 확인하지 않는 이 $(document).ready()와 $(window).on("load") 함수에 대해서 잠깐이나마 설명하는 시간을 갖도록 하겠습니다.

 

뭐, 생명주기라할것까진 아니고, 그냥 위 함수가 어떠한 순서로 웹사이트가 load되는지정도만 구경하도록 하시죠.


 

우선 $(document).ready()와 $(window).on("load") 함수가 어떤 역할을 하는지부터 짚고 넘어가시죠.

 

$(document).ready()

$(document).ready()의 경우 DOM(Document Object Model) 페이지가 JavaScript코드를 사용할 수 있을 때 실행이 됩니다. (참조)

 

* 잠시 보는 DOM이란?

DOM의 경우 Document Object Model로 한국어로 직역해보면 문서 객체 모델(...) 이며, 오늘 우리는 어려운 부분까지는 머리빠개지니까(??) 설명은 줄이고 그냥 쉽게 Front단에서 보여질 HTML이나 XML등의 문서를 객체로서 표현하여 가지고 있다고 생각을 하면 쉬울 것 같습니다.

이 DOM 덕분에 우리는 HTML을 JavaScript를 통해 요소나 속성등을 추가하고, 변경(삭제)를 할 수 있게됩니다.

 

$(document).ready() 코드

$(document).ready(function(){
	console.log("document ready!");
});

$(document).ready()함수의 매개변수로 실행시킬 function을 전달시킬 수 있습니다.

때문에 function을 위 코드와 같이 직접 선언을 하며 전달을 할 수 있고,

아래처럼 미리 다른곳에 만들어둔 function을 불러오는 방법도 사용할 수 있습니다.

$(document).ready(ready("document ready!"));

function ready(val) {
	console.log(val);
}

 

$(window).on("load")

$(window).on("load")의 경우에는 DOM을 포함한 모든 페이지가 준비가 되면 실행이 됩니다. (참조)

때문에 $(document).ready()보다 늦게 실행이 되는 모습을 보여줍니다.

 

$(window).on("load") 코드

$(window).on("load", function() {
	console.log("window load!");
});

$(window).on("load")함수는 위 $(document).ready()와는 조금 다른 모습을 띄고 있습니다.

예~~~~전 버전 jQuery에서는 $(window).load()와 같이 위 $(document).ready()와 거의 비슷한 형태를 띄고 있었으나, jQuery 버전(3.0 이상부터)이 올라가면서 .load()함수는 제거되었다고 합니다. (참조)

$(window).on("load") 또한 매개변수로 실행시킬 function을 넘겨줄 수 있습니다.

위와같이 선언과 동시에 전달을 하는 방법이 있고, 아래처럼 function을 불러오는 방법도 가능합니다.

$(window).on("load", function() {
	ready("window load!")
});

function ready(val) {
	console.log(val);
}

 

 

$(document).ready()와 $(window).on("load")의 실행 순서

위 코드를 직접 console에 찍어보면 아래와 같은 결과를 확인하실 수 있습니다.

 

console에서 찍어본다면.

위 설명에 적어놓은 것 처럼 DOM객체가 JavaScript를 실행할 수 있는 상태가 된다면 $(document).ready를, 모든 페이지에 대한 준비가 완료된다면 $(window).on("load")함수가 실행이 된다는걸 확인할 수 있습니다.

 

대략 이런느낌

실행 순서

 


음.. 내일부터는 또 한 주의 시작이네요.

코로나는 끝을 보이지 않고, 비도 많이와서 다들 지치실 것 같은데, 힘내시기 바랍니다.

모든분들 언제나 응원하고 있습니다!

 

Reference

- learn.jquery.com/using-jquery-core/document-ready/

 

$( document ).ready() | jQuery Learning Center

A page can't be manipulated safely until the document is "ready." jQuery detects this state of readiness for you. Code included inside $( document ).ready() will only run once the page Document Object Model (DOM) is ready for JavaScript code to execute. Co

learn.jquery.com

- jquery.com/upgrade-guide/3.0/#breaking-change-load-unload-and-error-removed

 

jQuery Core 3.0 Upgrade Guide | jQuery

jQuery Core 3.0 Upgrade Guide link Overview With the major version of 3.0, the jQuery Core team has taken the opportunity to make changes to clean up the API and fix bugs that may prove to be breaking changes for some code. This includes the removal of pre

jquery.com

 

버전정보 (v1.0)

 - v1.0 2020.08.03 배포

 

* 본 게시글의 이미지에 들어간 글씨체는 네이버 나눔 글씨체인 나눔스퀘어 Bold를 사용했습니다.

* 본 게시글의 이미지는 전부 (이미지 내의 픽토그램 등) 직접 제작했음을 명시합니다.

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

Karzin

abbeea@naver.com


[Swift5] 문제해결 : AVPlayer에서 Temp폴더 내 영상이 재생되지 않는 문제


몇 일전 개발 중 이런 문제가 생긴적이 있었습니다.

영상이 Temp폴더에 저장이 된 상태고, 이 Temp 폴더에 저장된 영상을 사진갤러리로 등록하고,

AVPlayer에 Temp폴더에 저장된 Path를 넣어줬는데도 재생이 되지 않는 문제(아무 반응이 없는 문제)가 있었습니다.

오늘은 이 문제를 어떻게 해결했는지 적어볼까 합니다.


원인

사람마다 조금씩 차이는 있을지도 모르겠는데, 저의 경우 사진갤러리로 영상을 등록하고 Temp성 파일을 삭제하는(ㅡㅡ)문제 였습니다. (사진갤러리로 영상 등록 후 바로 Temp 파일을 삭제하는 로직이 동작하는 문제)

뭐.. 조금만 분석해보면 나오는거긴했는데, 처음엔 AVPlayer에서 에러도 안뱉어내고 무슨문젠지도 모르는상태로 삽질만 죽어라고 했네요.. (AVPlayer에 이상한 Path넣어도 에러 안나오더라구요. 저는 나올줄 알았습니다;;)

혹시라도 영상이 재생이 안된다 싶으시다면 우선 지정된 영상 Path가 제대로 된 Path인지를 확인하시는걸 추천드립니다. 그리고 Path에 해당하는 파일이 있는지를 확인해보시는걸 추천드려요. 보통 exists 함수 사용하면 true/false로 떨어지니..

 

해결

언제나 원인만 알면 해결은 쉽습니다.

저의 경우 일단 임시방편으로 Temp성 파일을 삭제하는 로직을 주석처리 해두었는데요,

해당 부분은 나중에 Directory를 좀 더 세분화해서 어떻게 쓸건지 프로세스 등을 정해놓고 대대적인 공사를 하는걸로 하고 일단은 문제가 없도록 로직의 주석처리로써 해결을 해두었습니다.

 


어쩌다 한번씩 별거아닌거가지고 크게 삽질하는 경우가 있는데, 이번이 그 경우였네요 ㅋㅋㅋㅋㅋㅋㅋ

 

java와 차이가 있다보니 자꾸 헷갈..ㅋㅋㅋ

 

 

버전정보 (v1.0)

 - v1.0 2020.07.21 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com


Wireframe - 백문이 불여일견


깔끔하게 휴식을 마치고 와서 그런지 그나마 머리가 말끔해져서 오늘은 Wireframe을 소개해볼까 합니다. (?! 갑자기 ?!)

 

사실 제가 쓰는 이런 설계단의 문서들은 어려워하시거나 모르시는 분들이 많을 수 있습니다.

개발을 진행하시는 분들은 문서를 받아서 볼 수 있겠지만, 보기보다는 그냥 고객의 설명이나 상급 개발자의 설명만 듣고(회의 등) 변경된 내용으로 진행하는 경우가 많은 것 같더라구요.

그만큼 폭포수 모형보다도 애자일 방식을 택하는 기업도 많다는 의미이기도 하구요. (Prototype 만들고 수정하고 반복적인..)

 

사실 이 설계라는게 생각보다 시간도 잡아먹는거기도하고, 개발자에게 대충 '대략적인 혹은 완성된 UI' 그림만 던져주면 된다! 이런 부분이 없지않아 있어서 개발자는 그 대략적이거나 완성된 UI를 시작으로 개발-수정작업을 거쳐 완성본을 만드는 경우가 많은 것 같습니다. (ㅠㅠ)

저는 개인적으로 이런 부분들을 보완하고자 제가 개발하면서 개인적으로 만드는 문서들이기 때문에 어려워하시거나 잘 모르시는 분들도 많은 것 같습니다.

(사실 잘 찾아보면 소프트웨어 공학적인 부분에서 많은 내용을 찾아볼 수 있지만.. 개발 문서가 우선이다보니..)

 

근데 웃긴 사실은 이런 문서를 미리 만들어 두면 몇번의 수정만 거치면 완료 보고서 제출시에 편리해진다는 점이 장점이있습니다. (우려먹기? ㅋㅋㅋ)

또 설계서가 있는 만큼 개발을 진행해야하는 사람들에게도 이렇게 개발을 해야한다! 라는 프로젝트 개발 가이드 라인이 잡히다보니 같이 개발하는 동료나 후배들에게 입아프게 말할 필요도 많이 줄어 만족도는 꽤나 높은 편입니다. (개인적으로는 말이죠 ㅋㅋ)

물론 이해가 안되는 부분은 커뮤니케이션을 진행해야하지만 말이죠 ㅎ

 

음.. 벌써부터 말이 너무 많네요. 이런 주저리 거리는 부분은 본론에 들어가서 추가적으로 하도록 하고! 지금! 바로! 본론으로 들어가보겠습니다.


Wireframe?

Wireframe...? 그게.. 뭐예요...?

 

협업 중에 있어서도 Wireframe의 존재를 잘 모르시는 분들은 생각보다 많습니다.

그만큼 분석 및 설계시에 화면설계로 바로 넘어가는 경우는 많아도, Wireframe을 잡고 넘어가는 경우는 생각보다 드물기 때문에(ㅠ..ㅠ) 이런 경우가 생각보다 많이 발생하는 것 같습니다.

음.. 화면설계가 나오면 그나마 낫긴하지만, 이보다 더 심각한건 Wireframe이 확정되지 않은 상태에서 바로 디자인을 진행하는 경우는 생각보다 여러모로 힘들어집니다. (이러한 경우 Wireframe이 불안정하다보니, 바로 디자인을 시작하는 경우 여러번의 디자인 변경을 체험할 수 있습니다... 심한경우에는 서로의 이해관계가 통하지 않아 만족도가 낮은 완성본이 나올 가능성도 있습니다.ㅠㅠㅠ)

이런 경우 UI를 디자인 하는 디자이너, UI 목업이나 화면설계서만 보고 개발을 진행하던 개발자는 날마다 다크써클이 생겨나기 일쑤입니다. ㅇ_ㅇ;;;

이런 변경을 초기에 잡는 방법 중 하나가 개인적으로는 Wireframe이라 생각합니다.

 

그래서 Wireframe이 무엇이죠?

우선 어려운 내용들 다 접어두고 쉽게 설명하자면 기본 설계를 위한 '뼈대'입니다.

Wireframe을 잡아주면 거기에 쌓아 올리는 디자인적 요소든 개발적 요소든 어느정도 기본적인 '뼈대'가 잡혀있기 때문에 이후 구조적인 요소에서는 큰 변동사항이 거의 없어지게 됩니다.

사실 그 내면을 들여다보면 기획적인 요소가 조금 섞여있을 수 있는데, 이는 프로젝트의 제작을 원하는 사람의 생각을 '명확'하게 해주는 작업이기 때문에 그럴겁니다.

이 '명확'해진 '뼈대'위에 *구조물을 쌓아올리는 작업이 바로 디자이너와 개발자의 협업을 통한 분석-설계-개발이 진행 되는 거죠.

그만큼 Wireframe을 잡는건 굉장히 어려운 작업이기도 하지만, 한번 확실하게 잡아진 Wireframe 하나만 있으면, 이후 분석 설계 디자인 등은 굉장히 편리하고 빠르게 넘어갈 수 있습니다.

 

음.. 이렇게 말로만 하면 어려우니까 이쯤에서 비장의 카드 이미지를 넣어봐야겠네요.

직접 보시죠!

 

백문이 불여일견

백번 듣는거보다 한번 보시죠!

 

Wireframe (장비 관리 - 장비 등록)

장비관리 Wireframe, 만든이 : Karzin

위 이미지는 제가 Project.다원 Ensemble을 진행하면서 그렸던 Wireframe입니다. (참고 링크)

 

Project.다원 Ensemble_설계(5)_장비관리-장비등록 Wireframe&화면설계서(1)

Project.다원 Ensemble_설계(5)_장비관리-장비등록 Wireframe&화면설계서(1) 역시 저는 설계하다보면 괜한거 하나하나까지 꼼꼼히 따져가면서 하게되네요;;; 역시 귀찮은 성격,,,(?!?!?) 아니나다를까 설계�

karzin.tistory.com

 

사실 여기에는 제 개인적인 개발적 요소들이 들어가기도 했는데(Component의 종류), 이 문서 하나로 기획을 했던 저의 아이디어를 종합하고, 어떤식으로 개발을 해나가야할지 미리 '뼈대'가 잡아지고, 이렇게 진행을 해야겠다는 정보가 그림 하나로 완성이 된겁니다.

'뼈대'가 어느정도 작업이 완료되었다면, 이제 화면설계서가 굉장히 빠르게 나올 수 있는데, 이 화면설계서까지 나오면 사실 개발자에게 있어 이런 확정된(화먼설계서) 내용을 만드는 작업만큼 쉬운일은 또 없을겁니다.

그럼 Wireframe을 토대로 만들어진 화면설계서를 잠깐 구경을 해보실까요?

 

화면설계서(장비 관리 - 장비 등록)

장비관리 화면설계서, 만든이 : Karzin

화면설계서를 어떻게보면 한단계 위의 Wireframe과 비교를 해보면 크게 변경된 내용은 없어보입니다.

하지만 좀 더 그 내부를 살펴보면 Button Component는 '등록'이라는 text가 지정되어 변경되었거나, 이외에도 각 Component들의 사용의 예시를 보여줌으로써 개발자는 Wireframe과 비교를 해가며 알맞는 개발 Component를 선택하여 개발해 나갈 수 있게 해주는 것을 알 수 있습니다.

사실 이런 부분들이 제 입맛대로 바꾼 부분이 있어 조금 변칙적일 수는 있으나, 저의 경우 'Wireframe'단에서는 어떠한 Component를 사용할지 명확하게  뼈대를 잡아주고, 이후 해당 화면에 DB를 연동했을 때 어떤식으로 화면에 보일것인지를(뿌려줄 것인지를) '화면설계서'를 통해서 보일 수 있게 화면설계서를 마치 Prototype인 마냥 설계를 진행하는데, 이렇게 해주면 좋은점이 개발자 입장에서는 이 정도의 설계서만 있으면 이후에는 걱정없이 개발에만 집중할 수 있다는 점입니다.

물론 제가 진행중인 개인 프로젝트에서는 Wireframe과 화면설계서만으로 개발을 진행하지만 이는 기본적으로 Bootstrap을 사용함으로써 어느정도 디자인 단계를 보완할 수 있는 부분이라서 그런거기도하지만, 사실 여러가지 따지자면 디자인도 들어갈테고, Diagram같은 좀 더 개발의 기초를 잡아주는 부분도 있을 수 있으나, 이러한 부분들은 디자이너나 개발자간에 서로 협업(커뮤니케이션)을 하며 어떠한 디자인을 어떠한 로직으로써 어떻게 구현을 할지 머릿속에 상상하며 그려가야하는 작업이라고 생각하기 때문에, 자세한 언급은 삼가했습니다. (또 주저리주저리 말만 길어져서 다들 졸리게됩니다 ㅠㅠ)

 

이처럼 Wireframe을 한번 그려두면 자신의 생각을 남들에게 명확하게 전달할 수 있기 때문에 좀 더 자신이 원하는 프로젝트로 진행이 될 수 있는데, 물론 아쉬운 부분이 생길수 없다는 보장은 못하지만(기술적 요소 등으로 Wireframe대로의 개발이 힘든 경우 등등), 서로간 계속되는 커뮤니케이션을 통해 보완을 해나간다면 마지막에는 기획물에 걸맞는 마음에 드는 결과물을 뽑아낼 수 있습니다.

그만큼 Wireframe 자체가 굉장히 중요하기도 하구요.

 

* 위에서도 언급했지만(개발적 요소-Component의 종류), 항상 그렇듯 저는 제 개인적인 입맛대로 문서작성을 진행하기에 기존 Wireframe보다 변칙적인 부분이 많을 수 있습니다. 

* 이는 제가 좀더 개발자의 측면에서 바라보는 부분들과 개인적인 경험들을 토대로 변칙적인 부분으로써 발전한거이므로 양해부탁드립니다 ㅠ

 

 

그럼 Wireframe은 누가 만들어야 하나요??

이쯤오면 궁금해질겁니다. Wireframe은 매우 어려워보이는데 누가 만들어야할까요?

 

그 내면을 깊이 파고들면 Wireframe은 기획적인 요소가 많이 들어가 있기 때문에 기획자가 만들면 기획자가 원하는 굉장히 고퀄리티의 결과물을 뽑을 수 있을겁니다.

하지만, 생각보다 Wireframe을 쉽게 보기란 힘들 수 있는데요, 저는 생각합니다. 이럴때는 바로 유비무환(有備無患)이라는 사자성어가 있습니다.

그냥 누가 되었든 미리 준비해두시고 confirm을 받아야할 담당자에게 보여주는겁니다!

'우리는 지난 회의를 통해 이렇게 뼈대를 잡았으며, 때문에 담당자님께 이대로 진행해도 될지에 대해 confirm을 요청합니다. 맘에 드신다면 이대로 분석-설계-개발이 진행될 것입니다.' 라고요!

사실 이러한 경우에는 대체적으로 담당자에게도 아직 확고한 '뼈대'가 없거나, 어떻게 만들어야할지를 모르는 경우가 대다수입니다. 이럴때 이런식으로 만드려 하는데 진행해도 괜찮을까요? 라고 연락이 오는 만큼 반가운일은 특히나 없을겁니다.

분명 담당자는 확인을 하고 자신이 생각한(그려본) 내용과 비교를 해가며 어느정도의 피드백과 커뮤니케이션이 오가다보면 확고하게 '뼈대'가 잡혀나갈겁니다.

그만큼 커뮤니케이션에 시간이 많이 걸릴수도 있지만, 이런 확실한 '뼈대'가 완성되는 순간에는 분명 담당자에게 있어서는 굉장히 좋은 결과물로 남을 것입니다.

 

 

Wirframe의 장단점

마지막으로 Wireframe을 사용함으로써의 장단점을 한번 보시죠!

 

음.. 우선 단점부터 이야기해보겠습니다.

 - 시간적 Cost

 - 명확함의 어려움

 

하나씩 잡고 설명을 해보자면

첫번째로 시간적인 비용이 있습니다.

기획자-디자이너-개발자 간 서로의 커뮤니케이션으로 인해 잃을 수 있는 시간적인 비용을 말하는건데, 사실 이는 명확한 Wireframe의 설계로 분석/설계 단계에서 더 많은 시간적인 비용을 절약할 수 있어 어찌보면 양날의 검같은 존재입니다. 사실 이러한 부분은 제가 생각하고 경험하기로는 중간의 PM역할이 가장 중요하다고 생각을 하는데요, 커뮤니케이션의 중간에 서서 시간의 비용을 최대한 절약할 수 있는 방법을 숙련된 자신의 경험 등을 사용해 저울질해가며 작업을 원활하게 진행을 해주는 부분으로, 앞서 이야기 나온것처럼 경험에서 우러러 나오는 부분이 아닐까 생각하고 있습니다.

그만큼 분석/설계단계에서의 작업이 더뎌진다면 개발은 더더욱이 미뤄지게 될테니 시간적인 요소를 꼭 체크해가면서 커뮤니케이션을 하는게 가장 중요하지 않을까 합니다.

 

두번째로는 명확함의 어려움이 있습니다.

사실 명확하다는 말처럼 또 어려운게 어딨을까 싶네요. 말이 명확하다일뿐이지 보는 시각에 따라 명확하지 않음은 분명이 나타날테니 말이죠. 이러한 부분의 해결은 사실상 위에서 말한 커뮤니케이션을 통해 해결을 해나가는 방법밖에는 없다고 생각합니다. 분명 기획-디자인-개발- 등등 여러 관점에서의 시점은 각각 다르니까요.

 

 

그럼 이번에는 장점을 이야기해보도록 하겠습니다.

 - 시간적 Cost

 - 이후 작업이 용이 (스무스)

 - 인력의 최적화

 - 백문이 불여일견

 

첫번째 시간적인 비용부터 설명해보자면, 위의 단점처럼 장점과 단점이 될 수 있는 양날의 검인 부분입니다.

그만큼 잘 저울질해가면서 최상의 시간적 비용을 들이고 원하는 프로젝트로 이끌어가는 방법을 찾아가야하는게 최우선이라 보여집니다. 이런 부분은 어쩔수 없이 저에게는 부족한 경험에서 우러러나오는 부분이기 떄문에, 결국 조율은 경험자에게 유리할 수 있다 보여집니다.

 

두번째로는 이후의 작업이 용이(스무스)해진다는 부분입니다.

잘 만들어둔 Wireframe만 있다면, 이후 분석/설계문서는 기획의 의도가 정확하게 파악이 되었기 때문에 스무스하게 작업이 진행이 된다는 겁니다. 또 그만큼 잘 제작이 되었다면 개발까지도 큰 이슈없이 진행이 될거고, 빠른 Prototype이 나옴으로써 기획을 한 담당자도 검토를 통해 개발진등은 어느정도의 기간내 수용가능한 기능 변경이나 디자인 변경까지도 가능하다는 장점이 있을 수 있습니다. 물론 이런 기능이나 디자인의 변경에 한해서는 민감한 부분이 많이 있어서 변경에 대한 작업진행시에는 어느정도 서로의 커뮤니케이션을 통한 이해관계가 꼭 필요하겠지만 말이죠.

 

세번째는 인력의 최적화입니다.

인력이 많다면 분명 개발은 빠르게 진행될 수 있겠지만, 그렇다고해서 오버해서 넣을 필요는 없는 프로젝트가 많을텐데요, 이러한 경우 개발을 위한 설계문서가 제대로 잡힌다면 인력의 최적화 또한 이루어지게 됩니다. 해당 부분도 사실 경험자가 필요한 부분이긴 한데, 미리 각 인력의 시간당 개발 진행도를 미리 파악하고 알아둘 필요가 있고, 어느정도 파악이 된 경우 설계문서에 맞춘 각 개발인력을 최적화해서 배치할 수 있어 개발 인력을 정말 최적으로 부려(??)먹을 수 있습니다. 경험자가 필요한 만큼 이는 PL이나 PM의 역할이 중요한데, 그만큼 자신이 관리하는 인력의 실력등을 미리 파악하는 시간이 필요할 것입니다.

 

네번째로 백문이 불여일견입니다!

사실 이걸 저는 큰 장점으로 뽑고는 있는데, 이는 기획자의 의도를 백번의 말보다도 한번의 Wireframe으로써 상대방을 이해시킬 수 있다는 부분입니다. 우리는 커뮤니케이션을 진행할 때 항상 문제시 되는 부분은 서로 다른 성격의 사람들을 '이해'시켜야한다는 부분일겁니다. 자신의 의도를 명확하게 알려주고 상대를 이해시킴으로써 더 좋은 퀄리티의 프로젝트 완성물을 탄생시키는 것이죠. 사실 이러한 부분은 쉬운부분이 아닌만큼 굉장히 중요한 부분으로 자리잡고 있는데, 백번의 말보다 한번의 Wireframe으로 해결이 된다면? 이처럼 좋은 해결방법은 또 없을겁니다. (물론 이런 부분은 Wireframe의 완성도나, 추가적인 커뮤니케이션이 있을 수 있으나, 여러번의 커뮤니케이션을 최소화할 수 있는 좋은 방법이라고는 생각합니다.)

 

 

이처럼 우리에게 당장 필요한건 개발도 중요하지만, 분석/설계를 제대로 할줄 아는 기술도 중요하다고 생각합니다.

오늘은 Wireframe에 대해서 잠깐(???) 설명하는 시간을 가져봤는데, 좀 더 이미지를 많이 넣어서 졸음 방지를 해드릴껄(???) 하는 글이네요.

슬슬 졸음이 몰려올 시간일거라 오늘은 이쯤에서 마무리를 하도록 하겠습니다~


쓰면서도 알았지만 말 진짜 많이썼네요.

누가보려나 싶을정도로요 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

글을 읽어보시는 분들에게 큰 도움이 되려나 모르겠지만 되었으면 좋겠네요.

음.. 그래도 개인적인 경험과 공부를 토대로 작성을 하다보니 프로그램쪽으로 진출하는 새내기들에게는 조금이나마 유익한 글이 되지 않을까 싶습니다. 저 꼬꼬마때는 개발도 개발이지만, 기획단계부터 시작해서 분석이나 설계 등등 이런한 글을 읽어보고싶었는데, 없었어가지구..  Google에 'JAVA OOO만들기' 같은건 검색하면 쉽게 쉽게 나온다지만, 이런 기획부터 설계관련 이야기를 풀어놓은곳이 (제가 찾아봤을땐) 없었거든요.ㅠㅠ 제가 가진 경험과 공부한 내용들을 토대로 짜집기해서 머릿속에 나온거라 많은 부분 부족할 수 있지만, 한번쯤 읽어보시면 유익할거라 생각듭니다.

혹시 수정해야할 부분이라던가 있으면 댓글이나 메일주시면 확인해서 수정해두도록하겠습니다.

물론 질문도 항상 받고 있구요~

 

그럼 오늘 하루도 고생 많으셨습니다!

 

 

버전정보 (v1.1)

 - v1.0 2020.07.28 배포

 - v1.1 2020.07.28 장점에 새로운 항목 추가

 

* 본 게시글의 이미지에 들어간 글씨체는 네이버 나눔 글씨체인 나눔스퀘어 Bold를 사용했습니다.

* 본 게시글의 이미지는 전부 (이미지 내의 픽토그램 등) 직접 제작했음을 명시합니다.

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com




[Swift5] TableView 만들기 (custom cell을 만들어 보기)


저의 경우 아이폰 개발을 하면서 TableView를 많이 사용하게 되었는데, 덕분에 많은 부분 깨닳음(??)이 있었습니다.

오늘은 간단하게(?) TableView를 만들고 입맛에 맞춰 Custom Cell을 만드는 방법을 알아보도록 하겠습니다. 


Storyboard 작업

자, 우선 프로젝트를 생성해주시고, Main.storyboard를 선택합니다.

 

그리고 Component 중 Table View를 화면에 드래그해서 추가해줍니다. 

화면에 Table View Component 추가

 

다음으로 Table View에 보일 Cell(Table View Cell)을 앞서 만든 Table View 내에 추가해줍니다.

Table View에 Table View Cell 추가

 

Table View Cell 내 Content View 내부의 원하시는 Component를 추가해줍니다.

(여기서는 예시로 Image View, Label, Button을 추가했습니다.(왼쪽부터 순서대로))

Table View Cell 내 Content View에 원하시는 Component를 추가합니다.

 

이제 View Controller에 연결된 Class(Source 단)로 이동합니다.

(연결된 Class 정보를 잘 모르시겠다면, 처음 기본적으로 생성된 Controller의 Class는 보통 ViewController.swift입니다. 좌측에서 ViewController.swift 파일을 선택하시거나, 하단의 이미지처럼 ViewController의 Class를 확인 후 이동해 주세요.)

 

여기까지 따라오셨다면, Storyboard에서 초기작업이 끝났습니다.

단, 완벽히 끝난건 아니고, 이후부터는 Class(Source)와 Storyboard(View)를 왔다갔다하시면서 작업을 해야합니다.

 

ViewController Class 작업

처음 생성된 ViewController

 

Table View를 이용하기 위해서는 이동하신 Controller에 Table View를 동작하기 위한 Class를 상속받아야 합니다.

여기서는 Table View의 기능을 처리할 delegate(대리자) - UITableViewDelegate와 Tablew View Cell등을 제어하여 데이터를 처리할 datasource(데이터 소스) - UITableViewDataSource를 상속해줘야 합니다.

(저는 extension(확장)하는 방식으로 진행했습니다.)

 - UITableViewDelegate : Table View에서 Cell을 선택하거나, 어떠한 기능을 처리

 - UITableViewDataSource : Table View에서 Cell을 보여주기 위해 Table View의 Row나 Section은 어떻게 구현을 할것이며, Cell은 어떻게 만들어줄 것인지를 제어

   -> UITableViewDataSource 내에는 필수(Required) 함수들이 있습니다.

   -> func tableView(func tableView(UITableView, numberOfRowsInSection: Int) -> Int

   -> func tableView(UITableView, cellForRowAt: IndexPath) -> UITableViewCell

   -> 위 두 함수가 그것이며, 각각 section내에 몇개의 row가 있는지, 각 index별 cell의 정보를 어떻게 담고 있는지를 알려주기 위한 함수입니다.(하단 그림 참조)

 

ViewController를 extension(확장)하여 UITableViewDataSource, UITableViewDelegate를 상속시켜줍니다.

 

UITableViewCell Class 작업

이제 위에서 선언한 필수 함수 내부에 code를 구현을 해야겠죠!

하지만, 그 전에 우리는 UITableViewCell을 Return해줄 Class의 생성이 필요합니다.

그래서 우선은 code의 구현은 잠시 미루고 Class를 생성해주기로 합시다!

Cocoa Touch Class를 선택한 상태로 Next

Cocoa Touch Class 선택 -> Next

 

Class의 이름을 지어주고, 상속받을 Class를 선택해줍니다.

(편의상 Class의 이름은 CustomCell로 지었으며, Return할 UITableViewCell의 Class를 생성하고 있으니 상속받을 Class는 UITableViewCell을 선택해줍니다. - 하단 이미지 참조)

UITableViewCell을 상속하는 CustomCell을 만들어줍니다.

 

생성된 CustomCell Class.

UITableViewCell을 상속받는 CustomCell의 생성이 완료되었습니다.

 

이제 다시 Main.storyboard로 이동하셔서 Cell과 위에서 만드신 CustomCell을 연결해주는 작업을 합니다.

CustomCell의 Class 연결

그리고 Table View Cell의 Identifier를 지정해줍니다.

(여기서는 편의상 customCell로 지정했습니다.)

Tablew View Cell의 Identifier 지정

 

마지막으로 Main.storyboard와 앞에서 생성한 CustomCell.swift 파일을 나란히 열어두고,

기존에 만든 Component(ImageView, Label, Button)을 CustomCell Class에 선언해줍니다.

선언 방식은 Component를 마우스 우클릭하신 상태로 CustomCell Class(.swift)파일로 옮기시면 됩니다. - 하단 이미지 참조

화살표처럼 Componet를 마우스 우클릭한 상태로 소스단으로 드래그

 

자! 여기까지 오셨다면 Table View에서 Return해줄 Table View Cell Class는 다 만들어준겁니다!

 

ViewController Class 작업

이제 기존에 열어두신 화면 그대로에서 CustomCell Class 쪽만 ViewController Class로 변경해줍니다.

이 후 미리 Main.storyboard에 생성한 Table View를 제어하기 위해 위 Componet 선언한 방식처럼 Class(ViewController.swift)쪽에 선언합니다.(마우스 우클릭 한 상태로 드래그)

Table View를 제어하기위해 ViewController에 선언해줍니다.

 

마지막으로 CustomCell에 보여줄 Data와 code 생성합니다.

(하단 이미지의 소스코드는 게시글 아래쪽으로 더 내려보시면 설명과 함께 다시 정리되어있습니다.)

이제 code를 추가합니다.

 

cellName = String 형식으로, 위에서 정의한 Table View Cell의 Identifier 입니다. 저는 편의상 "customCell"로 지정하였으므로 cellName에는 "customCell" 대입해주고 있습니다.

cellTitle = Array 타입으로, ImageView의 iamge 정보를 나타냅니다. 더불어 Label의 text에 image값을 String 형식으로 넣어주기 위한 변수입니다.

 

viewDidLoad 함수의 [tableView_custom.delegate = self]

 - 기존에 선언해둔 TableView - tableView_custom에 delegate를 지정합니다.(self 즉, 소스 하단에 extension(확장)한 UITableViewDelegate의 정보를 대입합니다.)

viewDidLoad 함수의 [tableView_custom.dataSource = self]

 - 기존에 선언해둔 TableView - tableView_custom에 dataSource를 지정합니다.(self 즉, 소스 하단에 extension(확장)한 UITableViewDataSource의 정보를 대입합니다.)

 

extension ViewController class의 [func tableView(func tableView(UITableView, numberOfRowsInSection: Int) -> Int] 함수

 - 화면에 보여줄 row의 갯수를 나타냅니다. 여기서는 cellTitle.count 이므로 선언된 cellTitle 변수에는 3개의 값이 들어 있으므로 3을 return하게 됩니다.

extionsion ViewController class의 [func tableView(UITableView, cellForRowAt: IndexPath) -> UITableViewCell] 함수

 - 화면에 보여줄 cell을 지정합니다. function내에는 cellName("customCell")의 customCell을 선언했고, 이 customCell에 있는 Component imageView_custom과 label_custom의 정보(이미지, 텍스트)를 변경해주고 있습니다. (즉, Cell 내부 이미지와 텍스트는 짝이 되어 보일겁니다.)

 

완성된 프로젝트 Run

이제 완성된 프로젝트를 실행해 봅시다!

아이폰 11 Simulator


ViewController.swift

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView_custom: UITableView!
    let cellName:String = "customCell"
    let cellTitle : Array<String> = ["pencil.circle", "doc.circle", "bolt.circle"]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        tableView_custom.delegate = self
        tableView_custom.dataSource = self
    }

}

 

extension ViewController: UITableViewDataSource, UITableViewDelegate {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cellTitle.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let customCell = tableView_custom.dequeueReusableCell(withIdentifier: cellName, for: indexPath) as! CustomCell

        customCell.imageView_custom.image = UIImage(systemName: cellTitle[indexPath.row])
        customCell.label_custom.text = cellTitle[indexPath.row]

        return customCell
    }
    
}

cellName = String 형식으로, 위에서 정의한 Table View Cell의 Identifier 입니다. 저는 편의상 "customCell"로 지정하였으므로 cellName에는 "customCell" 대입해주고 있습니다.

cellTitle = Array 타입으로, ImageView의 iamge 정보를 나타냅니다. 더불어 Label의 text에 image값을 String 형식으로 넣어주기 위한 변수입니다.

 

viewDidLoad 함수의 [tableView_custom.delegate = self]

 - 기존에 선언해둔 TableView - tableView_custom에 delegate를 지정합니다.(self 즉, 소스 하단에 extension(확장)한 UITableViewDelegate의 정보를 대입합니다.)

viewDidLoad 함수의 [tableView_custom.dataSource = self]

 - 기존에 선언해둔 TableView - tableView_custom에 dataSource를 지정합니다.(self 즉, 소스 하단에 extension(확장)한 UITableViewDataSource의 정보를 대입합니다.)

 

extension ViewController class의 [func tableView(func tableView(UITableView, numberOfRowsInSection: Int) -> Int] 함수

 - 화면에 보여줄 row의 갯수를 나타냅니다. 여기서는 cellTitle.count 이므로 선언된 cellTitle 변수에는 3개의 값이 들어 있으므로 3을 return하게 됩니다.

extionsion ViewController class의 [func tableView(UITableView, cellForRowAt: IndexPath) -> UITableViewCell] 함수

 - 화면에 보여줄 cell을 지정합니다. function내에는 cellName("customCell")의 customCell을 선언했고, 이 customCell에 있는 Component imageView_custom과 label_custom의 정보(이미지, 텍스트)를 변경해주고 있습니다. (즉, Cell 내부 이미지와 텍스트는 짝이 되어 보일겁니다.)

 

 

CustomCell.swift

import UIKit

class CustomCell: UITableViewCell {

    @IBOutlet weak var imageView_custom: UIImageView!
    @IBOutlet weak var label_custom: UILabel!
    @IBOutlet weak var button_custom: UIButton!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        // Configure the view for the selected state
        
    }

}

앞서 마우스 우클릭 드래그를 통해 선언해준 Componet 정보들이 담겨있습니다.

Cell 내부 ImageView -> imageView_custom

Cell 내부 Label -> label_custom

Cell 내부 Button -> button_custom


간단(?)하게 설명만 하려했더니 생각보다 길어져버렸네요;;;

스터디 하는 김에 겸사겸사 하긴했는데.. 내용이 너무 길어져버려서..;;;

혹시 이해안가시면 댓글 작성해주세요. 최대한 다시 설명드리겠습니다 ㅠㅠ

 

 

버전정보 (v1.0)

 - v1.0 2020.07.22 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com


[Xcode] 에러해결 : Failed to register bundle identifier. The app identifier "~" cannot be registered to your development team because it is not available. Change your bundle identifier to a unique string to try again.


iOS개발을 하다보면 간혹 아래와 같은 문제를 만나볼 수 있습니다.

 

Showing All Messages

Failed to register bundle identifier. The app identifier "~" cannot be registered to your development team because it is not available. Change your bundle identifier to a unique string to try again.

 

위 에러에 대한 원인과 해결방안에 대해서 알아보도록 하겠습니다.


원인

또 에러..

에러만 뜨고 빌드 조차 진행이 안될건데, 해당 문제는 Bundle Identifier가 고유하지 않아 생기는 문제입니다.  (아마 이미 사용중인 경우가 거의일겁니다.)

 

 

해결

 

에러 메세지를 읽어보면 대충 이런 뉘앙스입니다.

bundle identifier의 등록을 실패했고, 앱의 identifier "~"를 사용할 수 없어 당신의 개발팀에 등록할 수 없으므로 , 당신의 bundle identifier를 고유한 문자열로 변경하고 다시 시도해보세요.

 

메세지처럼 Bundle Identifier를 변경해줌으로써 해결이 가능합니다.

(이미지의 inputbox부분을 고유한 Bundle Identifier로 변경)

 


위 에러.. 솔직히 어려운건아닌데,

저 푸릇푸릇한 개발 초보시절에는(지금도 초보지만..) 에러문장이 나와도 그냥 안되니까 당황해서 저거 하나가지고 엄청 시간잡아먹기도 했었습니다 ㅠㅠ (제가 바보라..)

그때 기억 생각나서 게시글 작성해보게되네요 ㅋㅋ;;

 

누군가에게는 도움이 되기를 바라면서..

 

 

버전정보 (v1.0)

 - v1.0 2020.07.21 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com


[Xcode] 에러해결 : iPhone is not available


아침부터 끙끙 앓고 있던 문제였는데,

실제 아이폰을 연결해서 테스트를 진행하려보니 iPhone is not available가 뜨고 진행이 안되는 문제가 있었습니다.

 

알고보니 Xcode와 iOS 버전이 맞지않아 그러는거라고..

(정확히는 SDK버전.)

 

오전중 계속 잡은거 치고 해결방법은 단순했는데, 저는 이걸 해결하겠다고 시간을 잡아먹기만.. (.......)

역시 사람은 모르면 검색을 해봐야합니다 ㅋㅋㅋ (저는 왜 검색안하고 계속 맥미니를 껏다키고 폰의 usb도 빼고껴고를 반복을 했는지...)

 


원인

위에서 언급한것처럼 Xcode에 있는 SDK버전이 맞지 않아서 그렇습니다.

저의 경우 금요일날 퇴근전에 아이폰을 업데이트를 진행해놓고 나갔는데 (iOS 13.5 -> iOS 13.6) 이게 원인이 되었습니다. ㅠㅠ

반나절간 재접속시키고 폰 연결해제도해보고 별짓을..

 

해결

해결방법은 쉽습니다.

1. 에뮬레이터로 테스트를 하거나,

2. iOS버전을 낮추거나 (...)

3. 위 해결방법들보다는 그냥 Xcode의 버전을 올려주는게 정답이겠죠? 

 - 찾아보니 iOS 13.6을 사용하려면 Xcode의 버전을 11.6으로 올려줘야합니다.

 - 지금 제가 사용중인 버전은 11.5이므로 Xcode의 버전올림이 필요하네요.

 

이유는 모르겠지만, 자동업데이트가 안되나봅니다.. (분명 가능했던거같았는데...)

 

저의 경우 App Store에서 직접 찾아서 다운로드 버튼눌렀습니다.

** 설치 전 혹시 모를 충돌을 방지하기 위해 켜져있는 Xcode와 에뮬레이터 그리고 폰의 연결을 해제해주세요.

 

xcode를 검색해서 설치 진행!

 


흠.. 아무래도 앞으로는 개발 테스트중일때에는 폰의 업데이트는 최대한 보류하는걸로..ㅠㅠ

 

버전정보 (v1.0)

 - v1.0 2020.07.20 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com


[Swift5] navigationController에서 뒤로가기 기능 만들기


navigationController에서 navigation의 back버튼처럼 UIButton에 뒤로가기 기능을 만들어야하는 경우가 있습니다.

이런경우 어떤식으로 코딩하면 될지를 알아보겠습니다.

 


코드

코드 자체는 굉장히 심플합니다.

@IBAction func onClick_btn_back(_ sender: Any) {
	self.navigationController?.popViewController(animated: true)
}

popViewController 함수를 사용해 현재 View를 Stack의 pop처럼 꺼냅니다.

해당 함수를 사용하면 navigation에 있는 뒤로가기 버튼과 같은 이벤트를 만들 수 있습니다.

(맨 위에 쌓여있는 View를 Pop합니다.)

animated 매개변수는 말그대로 뷰가 제거될때의 애니메이션 유무입니다.

 

 

Ref - Apple Developer Documentation

https://developer.apple.com/documentation/uikit/uinavigationcontroller/1621886-popviewcontroller

 

Apple Developer Documentation

 

developer.apple.com

 


버전정보 (v1.0)

 - v1.0 2020.07.17 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.co

+ Recent posts