개발 단상2013.11.10 22:24



현재 한국에 거의 유일한 소프트웨어 관련 정기 간행물!(내가 아는게 마이크로 소프트웨어 밖에 없는지도..)

마이크로 소프트웨어가 벌써 30 주년 이군요.

나보다 나이가 많아...


대학생 시절 도서관 정기 간행물 코너에 들어온 마소를 종종 보면서 처음 접했었죠.

여러모로 도움이 많이되는 잡지 마이크로 소프트웨어.

30주년 축하드립니다. 앞으로도 힘써 주세요!




책장의 마소들... 몇권은 어디로 갔지 -_-;;

Posted by 하품 - yawn 하품 - yawn
JAVA/Spring2013.10.17 16:24

해당 글에 사용된 토비의 스프링 3의 그림 및 소스 등에 대한 저작권은 이일민 님께 있습니다. 문제가 발생시 해당 글은 언제든지 내려질 수 있습니다.

해당 글은 이일민 님의 허락하에 작성되었습니다.

덧. 본인의 복습과 정리를 목적으로 작성하였기에 토비의 스프링을 읽지 않으셨다면 잘 안맞는 부분이 있을 수 있습니다.




토비의 스프링 1장은 초난감 DAO라 칭하는 하나의 DAO클래스를 보여주며 시작한다.


왜 초난감 DAO일까?

소스코드를 보면 기능 자체는 잘 작동한다. 하지만 잘 살펴보면 객체지향 설계원칙이 전혀 지켜지지 않았다.

특히나 (본인이 생각하기에) 객체지향 프로그래밍시 가장 먼저 우선되어야 할 '단일 책임의 원칙'이 완전히 깨져 있다.


1장의 내용은 이 초난감 DAO를 리팩토링 하면서 스프링의 중심철학(IoC 와 DI)을 설명하고 있다.

우선 다음을 기억하자.

관심사의 분리

관심이 같은 것기리는 하나의 객체안으로, 관심이 다른 것은 가능한 따로 떨어져서 서로 영향을 주지 않게 분리 하는 것.


관계설정 책임의 분리

특정한 동작을 하기위해선 여러 클래스끼리 관계를 맺어야 한다. 하지만 그런 관계를 맺는 메소드 등이 특정 클래스 안에 들어가 있다면 관계가 맺어진 클래스가 변경될 경우 수많은 클래스를 뜯어고쳐야 하는 일이 발생한다. 그렇기에 이러한 관계설정을 따로 분류한다.


토비의 스프링3를 예로 들자면 1장의 UserDao가 DB 커넥션을 하기위해 DConnectinoMaker와 클래스간 관계를 맺고 있다. 이는 ConnectionMaker 가 변경될경우 UserDao도 코드를 수정해야 하는 상황을 불러온다. 

이 클래스간 관계를 없애고 두 클래스간의 관계는 런타임시에 맺어지도록 하기위해 UserDao의 클라이언트(UserDaoTest)에 관계를 맺어주는 코드를 작성하였다. 즉 두 클래스간의 관계를 설정하는 관계설정 책임이 클라이언트(UserDaoTest)에 부과되었다.


개방페쇄 원칙

클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀있어야 한다.

코드는 변경하지 않으면서도 확장이 가능해야 한다.


높은 응집도와 낮은 결합도

응집도는 하나의 책임만을 담당하고 있는가를 뜻하고 결합도는 '하나의 오브젝트가 변경이 일어날 때 관계를 맺고 있는 다른 오브젝트에게 변화를 요구하는 정도' 라 말할 수 있다.

소프웨어 설계에서는 자신의 책임에 대한 응집도는 높고, 다른 객체와 맺은 관계에서는 결합도가 낮아야 한다.


1차적으로 리팩토링이 완료된 초난감 DAO의 다이어그램은 다음과 같다


(ConnectionMaker는 인터페이스)


UserDao에서 데이터베이스 커넥션 생성 책임이분리 되었다.

UserDaoTest란 클라이언트가 커넥션을 생성하여 UserDao에게 제공해 준다.

ConnectionMaker에는 전략 패턴이 적용되어 DConnectionMaker 뿐만 아니라 NConnectionMaker등도 사용 할 수 있다.

UserDao는 ConnectionMaker만 알고 있으면 된다.


언듯 보면 객체지향 원칙들이 잘 적용된 것 같지만 한가지 문제가 남아있다.

UserDaoTest가 테스트 책임 이외에 어떤 ConnectionMaker 구현 클래스를 사용할지 결정하는 책임이 같이 들어가 있다.

여기서 '객체의 생성 방법을 결정하고 그렇게 만들어지는 오브젝트를 돌려주는 팩토리 클래스'를 만들어 해결함으로써 리팩토링을 완료 한다.

이 팩토리 클래스(책의 DaoFactory 클래스)는 사용할 ConnectionMaker를 결정하고 이 커넥션을 사용하는 UserDao를 리턴한다.



이쯤에서 스프링에서 사용되는 몇가지 용어 및 개념에 대해 알아보자

제어의 역전(IoC)

간단히 설명하면 '모든 종류의 작업을 사용하는 쪽에서 제어하는 구조'를 거꾸로 뒤집은 것이다. 

제어의 역전에서는 모든 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않으며, 자신도 어떻게 만들어지고 어디서 사용되는지 알 수 없다. 모든 제어 권한을 자신이 아닌 다른대상에서 위임한다.

이 개념에 대한 자세한 내용은 역시 마틴 파울러의 글을 보는 것이 가장 좋다고 생각한다. 아래 링크는 그에 대한 포스팅이다.

http://vandbt.tistory.com/43

토비의 스프링에 나오는 소스로 이야기 하자면 본래 UserDao 에게 있던 제어권이 DaoFactory에 넘어가있다. DaoFactory가 UserDao가 사용할 오브젝트도 공급해주고, 구현하고 사용할 ConnectionMaker도 선택한다.


빈 bean (호지롷...)

스프링이 IoC 방식으로 관리하는 오브젝트라는 뜻. 스프링이 직접 그 생성과 제어를 담당하는 오브젝트만을 빈이라고 부른다.


빈 팩토리 bean factory

스프링의 IoC를 담당하는 핵심 컨테이너. 빈의 등록, 생성, 조회 등등... 빈을 관리한다


애플리케이션 컨텍스트 application context

빈 팩토리를 확장한 IoC 컨테이너. 빈 팩토리의 기본적인 기능에 스프링이 제공하는 각종 부가 서비스를 제공한다.

이 용어를 더 많이 사용한다

애플리케이션에서 IoC를 적용해서 관리할 모든 오브젝트에 대한 생성과 관계설정을 담당한다.




설정정보/설정 메타정보 configuration metadate

애플리케이션 컨텍스트 혹은 빈팩토리가 IoC 적용을 위해 사용하는 메타정보.


싱글톤 빈 스코프

스프링에서 기본적인 빈의 스코프는 싱글톤 스코프를 가진다. 즉 하나의 빈 오브젝트만이 생성되며 계속 재사용 된다는 의미 이다.



의존관계 주입(Dependency Injection)

  위의 블로그 포스팅 링크에서도 잠시 언급되었지만 IoC라는 용어는 굉장히 광범위한 용어이다. 그렇기에 스프링이 제공하는 IoC방식의 핵심을 짚어주는 의존관계 주입(DI)라는 의도가 명확한 이름을 사용하는 것이 좋다고 한다.

  그렇다면 의존관계 주입이란 무엇일까. 토비의 스프링 1장에서 작성된 코드를 보면 UserDao는 DConnectionMaker에서 제공하는 Connection을 사용하여야 한다. 즉 UserDao와 DConnectionMaker는 의존관계에 있다고 볼 수 있는데, 이 둘이 직접적인 의존관계를 맺는 것이 아니라 외부에서 이 둘의 의존관계를 맺어주는 것이다. 또한 UserDao는 ConnectionMaker인터페이스에만 의존관계를 만들어두어 낮은 결합도를 유지하고 있다.

  즉 코드만 보아서는 UserDao와 DConnectionMaker와의 의존관계를 알 수가 없으며, 런타임시 UserDaoFactory가 둘의 의존관계를 주입하여 준다. 이러한 사항을 정리하면 의존관계 주입이란 다음의 세가지 조건을 충종하는 작업이라 할 수 있다.


- 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야 한다.

- 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정한다.

- 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.


  UserDao를 보면 setConnectionMaker 라는 메소드가 존재한다. 이 메소드가 바로 의존관계를 주입받기위한 메소드 이다. 보통 set으로 시작하는 수정자 메소드(setter Method)를 이용하는 방식외애 생성자 메소드, 일반 메소드를 이용하여 의존관계를 주입받을 수 있다.


의존관계 검색(Dependency Lookup)

  외부로 부터 주입받는 DI가 아니라 스스로 의존관계를 검색하는 방식이 있다. 이를 의존관계 검색(DL)이라 부른다. 스프링이 사용된 코드를 보면 getBean() 이란 메소드를 볼 수 있다. 이 메소드가 DL을 이용하는 메소드이다. 

  DL은 언제 사용해야 할까? 스프링의 IoC와 DI컨테이너를 적용했다고 하더라도 어플리케이션의 기동 시점에 적어도 한번은 DL을 사용해 오브젝트를 가져와야 한다.  main()등의 메소드에서는 DI를 통해 오브젝트를 주입받을 방법이 없기때문이다.


스프링

  토비의 스프링 1장에서 만든 스프링이 적용되지 않은 코드만 보아도 충분히 DI가 작성되었다. 스프링은 그 코드중 UserDaoFactory에 작성된 정보들을 어노테이션이나 XML을 이용하여 설정정보로 읽어들여서 스프링이 직접 빈 오브젝트를 관리한다. 이때 사용되는것이 빈 팩토리와 어플리케이션 컨텍스트라 불리는 두가지 핵심적인 기능이다.

  스프링은 DaoFactory가 하는 일을 좀더 일반화 시킨것이며, 그 외에 직접 DaoFactory등을 구현해서는 활용하기 어려운 기능들을 쉽게 이용할 수 있게 해준다고 한다. 앞으로의 공부에서 이제 이런 기능들을 배우며 '왜 스프링을 사용하는가' 에 대해 더욱 정확히 알아갈 것이다.




샘플 코드

기존의 UserDao를 스프링의 코드로 변환한 소스는 다음의 깃허브 저장소를 참조하면 된다.

어노테이션, xml, 데이터소스를 이용하는 방법을 다 넣었다. 사용해보고자 하는 부분의 주석코드를 제거 하고 다른 코드를 주석처리 함으로써 각각의 방법으로 실행해 볼 수 있다.


https://github.com/maximinhan/mytobyspring3/tree/master/spring01


덧. DB는 직접 구현하셔야 합니다.



'JAVA > Spring' 카테고리의 다른 글

[spring] 2. 테스트  (0) 2014.02.20
[Spring] 1. 오브젝트와 의존관계  (0) 2013.10.17
[Spring] 스프링 정리 시작합니다.  (0) 2013.10.17
Posted by 하품 - yawn 하품 - yawn
JAVA/Spring2013.10.17 11:38

토비(이일민)님께 토비의 스프링의 일부 코드 및 그림등에 대해 사용허가도 받아놓고...

스프링 공부도 이미 시작해 놓구선 블로그에 대한 정리는 이제부터 시작합니다 -_-;;;;


준비는 한참전에 다 해놓고 시작이 너무 늦었어 Orz



현재 스프링은 3.2 버전까지 릴리즈가 되어 있고, 대략 내년을 기해 스프링 4가 릴리즈될 예정이라고 합니다.

그러나 제가 구입한 책은 토비의 스프링3 입니다. 구입하고 2주후에 토비의 스프링 3.1이 출시되더군요[.....]

(한참전에 구입했단 소리)


그래도 스프링의 패러다임, 구조 등이 크게 달라지진 않을 것이기에... 토비의 스프링3 를 가지고 하나하나 정리 이후 3.1과 그 이후 버전의 변경점 형태로 블로그에 정리해 나가고자 합니다.


글의 순서는 토비의 스프링3의 목차 순서와 동일합니다.

'JAVA > Spring' 카테고리의 다른 글

[spring] 2. 테스트  (0) 2014.02.20
[Spring] 1. 오브젝트와 의존관계  (0) 2013.10.17
[Spring] 스프링 정리 시작합니다.  (0) 2013.10.17
Posted by 하품 - yawn 하품 - yawn
iOS2013.09.25 18:32

iOS 6.0 부터 오토레이아웃이 적용되었다.

잘만 조정하면 코드한줄도 없이 다양한 상황에 대응되는 레아웃을 만들 수 있다.

하지만 언제나 원하는 대로는 되지 않는 법이고, 종종 코드로 오토레이아웃을 조절해 줘야하는 상황이 생긴다.

오토레이아웃을 코드로 조절하면 사실 코드가 굉장히 길어지고 헛갈리기 마련인데...

그것을 매우 쉽게 할 수 있는 오픈소스 라이브러리가 존재한다.


바로 Keep Layout 이다.

이 라이브러리는 다음의 깃 허브에서 받을 수 있다

KeepLayout


사용은 굉장히 간단한데 위 깃허브에서 source 폴더에 있는 파일을 모두 프로젝트에 포함시킨다.


xxxx.h 

#import <UIKit/UIKit.h>

#import "KeepLayout.h"/KeepLayout 사용을 위해 헤더에 포함


@interface xxxxController : UIViewController

@property (strong, nonatomic) IBOutlet UIView *superview_home;

@property (weak, nonatomic) IBOutlet UIButton *button_m1;

@property (weak, nonatomic) IBOutlet UIButton *button_m2;

@property (weak, nonatomic) IBOutlet UIButton *button_m3;

@property (weak, nonatomic) IBOutlet UIButton *button_m4;


@end


그리고 대략 위와 같이 오토레이아웃 적용을 받는 버튼 4개가 있다고 하자.

여기서 상황에 따라 각각의 버튼별로 Top Space를 변경하는 코드를 작성하고자 한다면

다음과 같이 사용할 수 있다.


xxxx.m

..... 이상 생략 ....

KeepAttribute *m1 = _button_m1.keepTopInset;

KeepAttribute *m2 = _button_m2.keepTopInset;

KeepAttribute *m3 = _button_m3.keepTopInset;

KeepAttribute *m4 = _button_m4.keepTopInset;

        

m1.equal = KeepRequired(90.0); //속한 뷰의 상단에서부터 90pt 간격을 가진다.

m2.equal = KeepRequired(150.0); //속한 뷰의 상단에서부터 150pt 간격을 가진다.

m3.equal = KeepRequired(200.0); //속한 뷰의 상단에서부터 200pt 간격을 가진다.

m4.equal = KeepRequired(300.0); //속한 뷰의 상단에서부터 300pt 간격을 가진다.

..... 이하 생략 .....


* iOS 6.0 부터 허용되는 형태의 코드로 작성되었습니다.

변경하고자 하는 오토레이아웃의 속성을 지정하여 KeepAttribute 라는 객체를 생성한다.

위의 코드에서는 최상단으로부터 떨어진 공간을 조정하기 위해 KeepTopInset메서드를 사용하였다.

넓이나 다른 속성 역시 위와같은형태로 사용하면 된다.

이렇게  KeepAttribute 객체를 생성후 해당 객체에 값을 넣어주면된다.

KeepRequired 등은 오토레이아웃 에서 Priority 값을 가지고 있는 메서드다 Required는 1000에 해당되고 그보다 낮은 high low 등도 존재한다.


이외 더욱 자세한 사항은 깃허브 페이지를 참조하면 된다.




Posted by 하품 - yawn 하품 - yawn
TroubleShooting2013.08.28 00:33


Q : 상황


sudoers에서 wheel 그룹의 계정에게 root권한을 주도록 옵션 설정 후 wheel 그룹 계정을 생성

톰캣 실행 스크립트의 기본 소유권은 root root 이기에 sudo 명령어를 이용하여 startup.sh 를 실행


Using CATALINA_BASE:   /usr/java/apache-tomcat-7.0.42
Using CATALINA_HOME:   /usr/java/apache-tomcat-7.0.42
Using CATALINA_TMPDIR: /usr/java/apache-tomcat-7.0.42/temp
Using JRE_HOME:        /usr/
Using CLASSPATH:       /usr/java/apache-tomcat-7.0.42/bin/bootstrap.jar:/usr/java/apache-tomcat-7.0.42/bin/tomcat-juli.jar

환경변수로 JAVA_HOME을 잡아 주었음에도 JRE_HOME이 제대로 설정되지 않음.


A : 해법

sudo 사용시 HOME, LOGNAME, PATH, SHELL, TERM, USER 를 제외한 모든 환경변수가 리셋 된다는 사실을 파악.
해당 부분은 sudoers 옵션중 Defaults env_reset 으로 인해 발생 하는 부분
해당 부분을 주석처리 하는 방법도 있으나, 기본설정은 그대로 두변서 특정 변수를 예외적으로 리셋하지 않도록 Defaults env_keep 옵션을 사용할 수 있다.

sudoers 를 다음과 같이 편집 하였다.

기존에 설정되어있는 Defaults env_keep 문구들 맨 아래에 다음과 같이 추가.
Defaults    env_keep += "JAVA_HOME CATALINA_HOME"


계정을 변경하여 sudo startup.sh 를 하였을 때 JRE_HOME이 정상적으로 들어가는 것을 확인.

Posted by 하품 - yawn 하품 - yawn
OS/Linux2013.08.27 22:15


집에 있는 컴퓨터를 외부에서 접속할 수 있는 서버로 만들어 봅시다.

서버로 사용할 컴퓨터엔 CentOS 6.4가 이미 깔려 있음을 가정 합니다.

사용 공유기는 ipTime n6004r 입니다.


접속 경로[?]를 보자면 다음과 같습니다.

 

            외부   ----------------------------    공유기   --------------------------   집 컴퓨터

                                                      (SK, KT등이 할당해준 ip)                           (CentOS Server)


공유기 설정으로 들어가면 (ipTime 기준 브라우저에서 192.168.0.1) 외부아이피 라는게 있을 겁니다.

외부에서 해당 ip로 접속 하면 공유기가 포트포워딩을 통하여 집에 설치된 서버로 포워딩을 해주고 해당 서버에서 웹페이지를 보여준다는 시나리오 입니다.



1. 우선 서버의 내부 ip를 고정시킵니다.

공유기 설정에서

고급설정 - 네트워크 관리 - 내부 네트워크 설정 으로 들어가서 수동 IP 할당 설정을 합니다.



여기서는 192.168.22.22 로 하였습니다.

수정합니다. 

192.168.0.222 로 하였습니다. 스샷대로 하지 마세요


공유기 설정이 끝났으면 서버의 ip 설정을 해줍니다


#] vi /etc/sysconfig/network-scripts/ifcfg-eth0

위의 명령어로 편집 창을 엽니다.

열어보면 CentOS 설치시 설정이나 퓨터의 환경 등등에 따라 조금씩 다르게 써있을 수 있습니다.

나오지 않은 부분은 패스 하고 다음과 같이 설정합니다.


BOOTPROTO="static"              //보통 dhcp로 되어있습니다. 고정 IP할당을 위해 static으로 바꿉시다"

IPADDR="192.168.0.222"           //공유기 설정에서 할당한 ip 입니다.

NETMASK="255.255.255.0"       

GATEWAY="192.168.0.1"          //공유기 주소

DNS1="8.8.8.8"                                

DNS2="8.8.4.4"


위 설정 중 DNS설정은 공유기 설정에서

고급 설정 - 네트워크 관리 -인터넷 연결정보

에 나오는 기본 DNS를 DNS1에 보조 DNS를 DNS2에 입력해 줍니다.

귀찮으면 위처럼 그냥 구글이 제공하는 DNS를 넣습니다.


설정 완료 후 저장.

그리고 service network restart 로 네트워크 서비스를 재시작 해줍니다.

그 후 ping 8.8.8.8 등으로 핑이 제대로 들어가는지 확인!

제대로 들어가면 완료 된 겁니다.


확실하게 하기위해 putty 등을 이용해서 접속도 해 봅시다.

ip는 내부 아이피인 192.168.0.222 포트는 22 입니다.


ps. 세팅하던 중 매우 멍청한 짓을 했습니다 -_-;;;;

192.168.22.22 로 설정 해놓고 보니 계속 network is unreachable 뜨고 기본 게이트웨이도 안잡히는 겁니다.

원인은 공유기에서 동적 ip 주소 범위가 192.168.0.2 ~ 192.168.0.254로 잡혀있는데... 그 범위를 넘어가는 ip를 설정해놓고 왜 안되나 하고 삽질한 것 -_-...

혹시나 제 멍청한 짓이 타산지석이 되도록 스크린샷은 바꾸지 않았습니다 ㅠㅠ



2. jdk와 tomcat 설치

이부분은 구글링하면 워낙 많기도 하고, 프로그래밍좀 해봤다 하면 워낙 많이 하는 부분이니 그냥 슝슝 넘어가겠습니다.

환경변수 설정 정도나 작성해 두겠습니다.


vi /etc/profile 을 하여 맨 밑에 다음과 같이 작성해 주세요.

JAVA_HOME=/usr/java/jdk1.7.0_25

CATALINA_HOME=/usr/local/apache-tomcat-7.0.42

PATH=$PATH:$JAVA_HOME/bin

그후 커맨드에서 source /etc/profile



3. 방화벽 열기.

2번까지만 한 후 톰캣이 설치된 폴더의 bin ($CATALINA_HOME/bin) 에 가서 톰캣을 실행 시켜주면 실행이 됩니다.

다만 지금 상황에선 외부에서도 내부망에서도 접속을 할 수 없습니다.

톰캣이 사용하는 8080포트가 centos의 기본 방화벽에 막혀있기 때문입니다.

iptables를 편집하여 포트를 열어줍시다


vi /etc/sysconfig/iptables  로 파일을 연 후

-A INPUT -m state -state NEW -m tcp -p tcp --dport 8080 -j ACCEPT

를 추가해 줍니다.

그리고

service iptables restart 로 재실행하면 완료 됩니다.


이제 내부망에서 http://192.168.0.222:8080 을 브라우저 주소에 입력하면 톰캣 시작 페이지가 뜨는걸 볼 수 있습니다.



4. 포트포워딩 및 ddns 등록

이제 마지막으로 외부에서 접속이 가능하도록 포트포워딩을 해주고 ddns서비스를 신청해야 합니다.


보통 가정에서 쓰는 인터넷은 유동ip가 할당이 되기 때문에 지금 할당된 ip로는 현재 접속이 된다고 해도 언제 접속이 안될지 알 수 없습니다.

이를 해결하기위해 주기적으로 변경된 ip와 사용자가 설정한 인터넷주소를 매칭시켜주는 서비스가 ddns서비스 입니다. 

많이 알려진 무료 ddns서비스로는 DNSever 등이 있는데요? 

저는 ipTime 공유기를 쓰다보니 공유기 1개당 ipTime에서 ddns서비스를 제공해 주더군요.


고급설정 - 특수기능 - DDNS 설정 으로 들어갑니다.

위 화면에서 호스트이름 abcdefd.iptime.org 이런 형태로 지어주시고 계정과 암호 할당 한 뒤 추가를 누릅니다.


그럼 화면에서와 같이 밑에 등록이 되는데요? 등록확인중 어쩌구 뜨면 접속상태 다시보기를 눌러줍시다.

그럼 정상등록이 되었다고 나올 겁니다.


이제 포트포워딩을 할 차례 입니다.


고급설정 - Nat/라우터관리 - 포트포워드 설정

으로 들어간 후

규칙이름 뭐 아무렇게 나 정해 주시고 

내부 IP는 192.168.0.222

프로토콜은 TCP

외부포트는 저는 :8080 을 생략하기 위해 80-80으로 하였습니다.

내부 포트는 톰캣이 실행되는 포트가 8080 이므로 8080해주셔야 합니다.


이렇게 완료 한후 이제 위에서 DDNS설정에서 설정해준

설정한이름.iptime.org 로 접속하면 이제 외부에서도 동일한 톰캣 화면을 볼 수 있습니다.


Posted by 하품 - yawn 하품 - yawn
DATABASE/sqlite2013.08.21 16:54


sqlite_bind_text(), sqlite_bind_text16(), sqlite_bind_blob() 

의 세 함수는 다른 바인드 함수보다 파라메터의 수가 좀더 많다.


텍스트를 기준으로 원형은

int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));

이다.


여기서 첫번째 인자는 statement 핸들이다.


두번째 인자는 데이터가 들어갈 순서이다.

~~~ values(?,?,?,?) 식으로 구성이 되어있을때 맨 좌측 ?표가 1번째 물음표이다. 두번째 인자가 3 이라면 맨좌측으로부터 세번째 ?표에 데이터를 넣으라는 뜻.


세번째 인자는 db에 넣을 데이터 이다.


네번째 인자는 세번째에서 지정한 데이터의 크기를 정한다. -1(음수)를 넣으면 전체 데이터를 넣는다.


다섯번째 인자는 특별한 인자 이다.

들어가는 값으로 SQLITE_STATIC 과 SQLITE_TRANSIENT가 있다.

SQLITE_STATIC의 경우 바인딩 되는 변수를 static변수(free가 될 일이 없는)로 사용한다는 의미 이다.

변수가 중간에 변경되거나 메모리가 해제 되면 문제가 발생할 수 있다.


SQLITE_TRANSIENT는 바인딩 변수가중간에 변경이 될 수도 있기에 해당 변수값을 복사하여 사용한다. 중간에 변수가 변경이 되어도 복사한 값으로 사용되기에 문제없다.

다만 복사과정이 들어가기에 안전하나 SQLITE_STATIC 보다는 속도가 느리다




'DATABASE > sqlite' 카테고리의 다른 글

[sqlite] sqlite_bind_text() (blob, text16...) 인자 값  (0) 2013.08.21
Posted by 하품 - yawn 하품 - yawn
iOS2013.08.20 16:50


sqlite사용할 때(혹은 그 이외에도) 앱 내에서 직접 데이터베이스를 다 만들어 주는것 보다 파이어폭스의 sqlite manager등으로 기본 틀을 만들어 주고, 그렇게 생성된 디비파일을 앱에 추가하여 사용하는게 편하다.

다만 그냥 xcode에서 추가한 상태로 사용하면 해당 파일은 읽기 전용파일이 되므로

번들(간단하게 개발자가 만든 리소스의 모음, Nib파일등등)에서 앱내의 Document폴더로 이동이나 복사를 한 후 사용해야 한다.


파일을 복사하는 코드는 다음과 같다


    NSArray *documentArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,

                                                                NSUserDomainMask,

                                                                YES);

    NSString *documentsDirectory = [documentArr objectAtIndex:0];

    //document 디렉토리의 위치를 알아낸다.

    NSString *documentDBPath = [documentsDirectory stringByAppendingPathComponent:@"seoul.sqlite"];

    //sqlite 파일이 위치할 path 설정

    

    NSFileManager *filemanager = [NSFileManager defaultManager];

    

    BOOL dbexists = [filemanager fileExistsAtPath:documentDBPath];

    if (!dbexists) { //document내에 sqlite 파일이 없다면 번들에서 복사한다.

        NSString *bundleDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"seoul.sqlite"];

        NSLog(@"bundle db %@",bundleDBPath);

        //번들, 개발자가 직접 만든 sqlite 파일의 위치

        NSLog(@"docu db %@", documentDBPath);

        //sqlite 파일이 복사될 도쿠먼트의 위치

        

        NSError *error;

        BOOL success = [filemanager copyItemAtPath:bundleDBPath toPath:documentDBPath error:&error];

        //파일을 복사하는 부분

        

        if (!success) {

            NSLog(@"error : %@",[error localizedDescription]);

        }

    }


여기서 주의할 부분이 몇가지 있는데

NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

사용시 xcode 자동완성을 사용하다보니 NSDocumentationDirectory로 사용하는 경우가 종종 있다.

NSDocumentDirectory라 되어있는지 반드시 확인하자


이 외에도 디렉토리와 파일명을 합하는 메소드를 사용할 때

[documentsDirectory stringByAppendingPathComponent:@"seoul.sqlite"];

stringByAppendingString 을 사용하는 경우가 종종 발생한다. 이럴 경우 에러가 나니 반드시 확인하자.

Posted by 하품 - yawn 하품 - yawn
개발툴...2013.08.04 18:08


메이븐 라이프사이클에 대해 정리된 블로그 링크


- 메이븐의 라이프 사이클은 Default, Clean, Site 의 세 가지가 있다.

- Phase는 각 라이프사이클의 빌드 단계만을 정의, 해당 단계의 어떤 동작은 연결된 Plug-In 으로 실행됨

- Goal은 Ant의 타겟 이라고 한다... 대략 특정 Phase에서 동작할 플러그인을 구동시키는 명령어 정도로 이해하면 된다고 생각한다.


각 단계의 Phase 에 대한 설명


Default Lifecycle


 validate

 프로젝트가 정확한지, 필요한 정보를 모두 이용할 수 있는지 확인 

 initailize

 빌드 상태를 기화

 generate-sources

 컴파일에 포함되는 소스 코드 생성

 process-sources

 소스 코드 처리

 generate-resources

 패키지에 포함되는 리소스 생성

 process-resources

 리소스를 패키지를 준비할 디렉토리에 복사 및 처리

 compile

 프로젝트의 소스 코드를 컴파일

 process-classes

 컴파일에서 생성된 파일의 후처리

 generate-test-sources

 컴파일에 포함되는 테스트 소스 코드 생성

 process-test-sources

 테스트 소스 코드 처리

 generate-test-resources

 테스트를 위한 리소스 생성

 process-test-resources

 테스트 데스티네이션 디렉토리에 리소스를 복사 및 처리

 test-compile

 테스트 소스 코드를 컴파일하고 컴파일된 테스트 소스 코드를 테스트 데스티네이션 디렉토리로 이동

 process-test-classes

 테스트 컴파일에서 생성된 파일의 후처리

 test

 적절한 단위테스팅 프레임워크로 테스트 실행

 prepare-package

 패키지 전에 패키지를 준비하기 위해 필요한 동작 실시

 package

 컴파일된 코드를 배포 포맷에 게 패키지

 pre-integration-test

 통합 테스트 실행 전에 필요한 션 수행

 integration-test

 통합 테스트가 실행할 수 있는 환경에서 처리 및 패키지 배포

 post-integration-test

 통합 테스트 실행 후 필요한 액션 실시

 verify

 패키지가 유효하고 질을 만족하는지 증하기 위해 확인

 install

 로컬 저장소에 패키지 설치

 deploy

통합, 릴리즈 환경에서 작업 종료 후 최종 패키지를 외부 저장소에 복사


Clean Lifecycle


 pre-clean

 프로젝트를 clean 하기 전에 필요한 프로세스를 실행

 clean

 전 빌드에서 생성된 모든 파일 삭제 

 post-clean

 프로젝트를 clean 한 후에 필요한 프로세스를 실행


Site Lifecycle


 pre-site

 프로젝트 사이트 생성 전에 필요한 프로세스 실행

 site

 프로젝트 사이트 문서 생성

 post-site

 사이트 생성 후, 사이트 배포 전에 필요한 프로세스 처리

 site-deploy

 생성된 사이트 문서를 웹 서버에 배포


Posted by 하품 - yawn 하품 - yawn
개발툴...2013.08.04 17:29


최근 메이븐 공부를 하면서 이를 어떻게 정리하고 기억하면 좋을까 고민하다가...

정리가 매우 잘 되어있는 분의 블로그를 찾게되어 그 주소를 링크합니다.


http://gt1000.tistory.com/category/maven



Posted by 하품 - yawn 하품 - yawn
javascript/Example2013.07.10 18:03

javascript에서 날짜 관련된 코딩을 할때... 그 때 마다 날짜 포맷 정해주고 중간에 0 넣고 빼고 어쨋뜬 으아아아앙 귀찮아서

혹 누군가 관련된 라이브러리나 코드를 만들어놓지 않았을가 검색하다가 찾아냈다.

(사실 내가 만들어보겠다고 짜다가 포기)


원본 출처는 이곳

http://www.codeproject.com/Articles/11011/JavaScript-Date-Format



// a global month names array
var gsMonthNames = new Array(
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
);
// a global day names array
var gsDayNames = new Array(
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday'
);
// the date format prototype
Date.prototype.format = function(f)
{
    if (!this.valueOf())
        return ' ';

    var d = this;

    return f.replace(/(yyyy|mmmm|mmm|mm|dddd|ddd|dd|hh|nn|ss|a\/p)/gi,
        function($1)
        {
            switch ($1.toLowerCase())
            {
            case 'yyyy': return d.getFullYear();
            case 'mmmm': return gsMonthNames[d.getMonth()];
            case 'mmm':  return gsMonthNames[d.getMonth()].substr(0, 3);
            case 'mm':   return (d.getMonth() + 1).zf(2);
            case 'dddd': return gsDayNames[d.getDay()];
            case 'ddd':  return gsDayNames[d.getDay()].substr(0, 3);
            case 'dd':   return d.getDate().zf(2);
            case 'hh':   return ((h = d.getHours() % 12) ? h : 12).zf(2);
            case 'nn':   return d.getMinutes().zf(2);
            case 'ss':   return d.getSeconds().zf(2);
            case 'a/p':  return d.getHours() < 12 ? 'a' : 'p';
            }
        }
    );
}

String.prototype.times = function(n) {var s = '';for (var i = 0; i < n; i++) s += this; return s;}
String.prototype.zf = function(len){return "0".times(len - this.length) + this;};
Number.prototype.zf = function(len){return this.toString().zf(len);};
SomeDiv.innerText = (new Date()).format('dddd, mmmm dd, yyyy.');
형태로 사용하면 된다.

한국에 맞게 상요하려면 위의 요일 영문 부분들을 월요일, 화요일 등으로 바꿔주면되고... 월 이름은 사실 필요없다 -_-;;


그리고 이미 그렇게 만들어놓으신 분이 계심

http://stove99.tistory.com/46

Posted by 하품 - yawn 하품 - yawn
CSS2013.07.10 16:58


흔이있는 경우는 아니겠지만... 특정 엘레먼트의 Height를 어떤 상황에서도 세로 길이가 웹 브라우저의 전체가 되어야 할 때가 있다.

하지만 보통 <div> 태그가 하나 있고 그 <div>태그에 'height:100%'를 주면 <div>박스 안의 컨텐츠의 높이가 <div>의 Height가 된다.


이를 해결하려면 다음과 같이 코딩을 해야 한다.


HTML 코드
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>100%<⁄title>
<link rel="stylesheet" type="text⁄css" href="style.css">
<⁄head>
<body>
<div id="content">
첫번째는 안쪽 초록색 블록의 크기를 정확히 알고 있을 때 사용하는 방법입니다.<br>
시작 지점을 50% 내린다음에, 블록크기 절반만큼 위로 마이너스 마진을 준 것이죠.<br>
크기를 모를때는 사용할 수 없습니다.<br>
<br><br><br>
그래서 크기와 상관없이 무조건 세로 중앙정렬을 사용하는 방법으로는 두번째 방법을 사용하셔야 합니다.<br>
<br><br><br><br>
하지만... 여기서 또 문제가 발생하는 부분이 있는데요?<br>
float:left, float:right 등으로 플로팅 된 박스 모델의 경우 세로정렬이 또 제대로 동작을 하지 않는다는 겁니다.<br>
<br><br><br><br>
미치겠네요.<br>
그래도 방법은 있습니다. <br>
첫번째 방법처럼 position 속성을 조정함으로써 일일이 다 컨트롤해 주던가, table 구조로 만들어 버리면 됩니다.<br>
<br><br><br><br>
다음은 그 대망의 완성본 입니다.
첫번째는 안쪽 초록색 블록의 크기를 정확히 알고 있을 때 사용하는 방법입니다.<br>
시작 지점을 50% 내린다음에, 블록크기 절반만큼 위로 마이너스 마진을 준 것이죠.<br>
크기를 모를때는 사용할 수 없습니다.<br>
<br><br><br>
그래서 크기와 상관없이 무조건 세로 중앙정렬을 사용하는 방법으로는 두번째 방법을 사용하셔야 합니다.<br>
<br><br><br><br>
하지만... 여기서 또 문제가 발생하는 부분이 있는데요?<br>
float:left, float:right 등으로 플로팅 된 박스 모델의 경우 세로정렬이 또 제대로 동작을 하지 않는다는 겁니다.<br>
<br><br><br><br>
미치겠네요.<br>
그래도 방법은 있습니다. <br>
첫번째 방법처럼 position 속성을 조정함으로써 일일이 다 컨트롤해 주던가, table 구조로 만들어 버리면 됩니다.<br>
<br><br><br><br>
다음은 그 대망의 완성본 입니다.첫번째는 안쪽 초록색 블록의 크기를 정확히 알고 있을 때 사용하는 방법입니다.<br>
시작 지점을 50% 내린다음에, 블록크기 절반만큼 위로 마이너스 마진을 준 것이죠.<br>
크기를 모를때는 사용할 수 없습니다.<br>
<br><br><br>
그래서 크기와 상관없이 무조건 세로 중앙정렬을 사용하는 방법으로는 두번째 방법을 사용하셔야 합니다.<br>
<br><br><br><br>
하지만... 여기서 또 문제가 발생하는 부분이 있는데요?<br>
float:left, float:right 등으로 플로팅 된 박스 모델의 경우 세로정렬이 또 제대로 동작을 하지 않는다는 겁니다.<br>
<br><br><br><br>
미치겠네요.<br>
그래도 방법은 있습니다. <br>
첫번째 방법처럼 position 속성을 조정함으로써 일일이 다 컨트롤해 주던가, table 구조로 만들어 버리면 됩니다.<br>
<br><br><br><br>
다음은 그 대망의 완성본 입니다.
<⁄div>
<⁄body>
<⁄html>

CSS 코드
html {
	height:100%;
}
body {
	margin:0px;
	padding:0px;
	height:100%;
}
#content {
	background: gray;
	border-left: 1px solid #000;
	border-right: 1px solid #000;
	padding: 20px;
	margin: auto;
	width: 900px;
	min-height: 100%;
}



중요한건 html과 body의 height:100%와, content의 min-height:100% 이다.

content에 min-height 로 주는 이유는 div박스 안의 내용이 브라우저 현 화면의 100%... 즉 한 화면을 넘가 있을 경우 그냥 100%를 주게되면 화면을 넘어가 있는 부분에 대해선 속성 적용이 안된다.

'CSS' 카테고리의 다른 글

[CSS] 100% Height  (1) 2013.07.10
[CSS] css를 이용한 가로 중앙, 세로 중앙 정렬  (0) 2013.03.27
Posted by 하품 - yawn 하품 - yawn
JAVA2013.07.09 17:23

- 이해한 부분들로 JVM에 관해 정리 하였으나, 정확하게 이해했다고 확답할 수 없습니다.

- 혹 이 포스팅을 보시는 분들께서 잘못된 부분을 지적해주시면 감사하겠습니다.


1. JVM 메모리 구조


- Class Area (Method Area)

- Java Stack

- Heap

- Native Method Stack



2. Class Area (Method Area)

JVM의 모든 Thread가 공유하는 영역.

JVM에 의해 로딩된 클래스들이 저장됨.

구현된 메소드들이 저장됨.

클래스 변수들이 저장됨.

적재된 클래스의 모든 Property는 변경되지 않음.


3. Java Stack

Method가 호출될 때마다 Stack Frame이 생성. 

Java Stack Frame이 모여 Java Stack 이 된다.

Java Stack 의 최상단은 Active Java Stack 이다.

수행되는 Method 정보, 지역변수, 매개변수, 연산 중 발생하는 임시데이터 저장.

하나의 Thread에 각각 Java Stack 이 존재한다.


4. Heap

자바의 객체(인스턴스)들은 여기에 저장된다.

Heap 은 다음과 같이 3영역으로 다시 나뉜다.

   - Permanent Space : JVM 클래스, Constant Pool, 메소드, 등을 위한 영역

   - Young 영역 : 새로생긴 모든객체를 위한 영역

      Eden : 새로 생성된 객체의 영역

      Survivor 1, 2 (from, to) : 새로 생생된 객체들이 시간이 지나 OLD 영역으로 가기전 머무리는 영역

   - OLD 영역 :  생성된지 오래된 객체들의 영역, Full GC의 대상이 된다.


5. Native Method Stack

Native 메소드를 위한 영역.

JVM 명령이 아닌 다른 언어로 구현되어 있다(보통 C언어)

Java Native Interface를 이용해 다른 언어와 연동할 수 있음.



- 참조 링크

http://dryang.egloos.com/4005363




Posted by 하품 - yawn 하품 - yawn
iOS2013.06.25 12:18

NSDate 는 특정날짜(2001년 1월 1일 자정)를 기준으로 객체에 설정된 날짜 까지의 기간을 초단위로 계산하여 저장하고 있다.

그렇기에 단순한 NSDate 객체로는 년, 월, 일 등의 날짜 값을 얻을 수 없다.


각각의 날짜값을 얻기위해선 다음과 같이 NSCalender 와 NSDateComponents 를 이용해야 한다.


NSDate *now = [NSDate date]; //현재 날짜로 객체 생성

NSCalendar *calender = [NSCalendar currentCalendar]; //캘린더 객체생성

unsigned int calendarFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit;

//NSYearCalendarUnit, NSMonthCalendarUnit, NSWeekCalendarUnit, NSDayCalendarUnit, NSHourCalendarUnit, NSMinuteCalendarUnit, NSSecondCalendarUnit;

//, , , , , 각각 얻기위한 플래그들 예제는 ,,일만 사용

NSDateComponents *dateComponent = [calender components:calendarFlags fromDate:now];

//플래그를 이용해 각각의 구성요소를 가져오는 객체

    

NSLog(@" - %d",[dateComponent year]);

NSLog(@" - %d",[dateComponent month]);

NSLog(@" - %d",[dateComponent day]);

//현재 날짜의 일이 각각 찍힌다.


플래그를 사용하지 않으면 엉뚱한 값이 도출되니 주의하자.



기타 NSDate에 관련한 여러 내용은 밑의 블로그를 참조. 애플이 제공하는 레퍼런스를 보는게 가장 좋지만... 영어의 압박...ㅠㅠ


http://soooprmx.com/wp/archives/2335


Posted by 하품 - yawn 하품 - yawn
iOS2013.06.17 18:45

iOS 5.0 이전에서는 뷰 컨트롤러의 특정 방향만 회전하도록 제어하는 코드는 다음과 같았다.


#pragma mark iOS5 rotate

- (BOOL)shouldAutorotateToInterfaceOrientation:

(UIInterfaceOrientation)interfaceOrientation

{

    return (interfaceOrientation == UIInterfaceOrientationPortrait);

    // 세로보기만 지원

    

    //return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);

    //거꾸로 들기 빼고 허용

}


하지만 위의 shouldAutorotateToInterfaceOrientation: 메소드가 iOS 6.0 부터 Deprecated 되었다.


6.0에서는 화면의 자동회전 여부를 단순히 shouldAutorotate 란 메소드로 결정한다.

- (BOOL) shouldAutorotate

{

    return YES;//자동회전 허용

    //return NO; //자동회전 비허용

}


위 메소드가 YES를 리턴할 때, 즉 자동회전이 허용될때 회전히 허용되는 화면(세로, 가로 왼쪽, 가로 오른쪽, 거꾸로)의 설정은 xCode의 프로젝트 요약 화면(정확한 명칭을 모르겠음)에서 설정할 수 있다



Target 에서 Summary를 눌렀을 때 볼수 있는 화면이다.(보통 프로젝트를 생성하면 처음 볼수있는 화면)

기본적으로 위의 스샷에서처럼 세로, 가로 양옆이 눌려있으며 이것이 shouldAutorotate가 YES를 리턴 할 때 전환이 허용되는 화면이다.


물론 위화면에서 눌러준 것과 별개로 각 UIViewController별로 허용 화면을 설정해 줄 수 있다.

- (NSUInteger) supportedInterfaceOrientations

{

    return UIInterfaceOrientationMaskPortrait//세로 화면만 허용

    //return UIInterfaceOrientationMaskAll //전체 화면 허용 

    //return UIInterfaceOrientationMaskPortraitUpsideDown //거꾸로만 허용

    //return UIInterfaceOrientationMaskLandscape; //가로화면만 허용

}


위의 코드와 같이 각 뷰별로 허용 화면을 설정하면 되나 이 때 주의 점이 있다.

화면 전환시 코드보다 프로젝트 요약화면(위의 스샷)에서 눌러준 허용화면을 우선시 한다. 즉 코드로 허용 화면을 설정할 땐 요약화면에서 허용된 화면 안에서만 조작이 가능하다.


예를 들어 위 스샷처럼 세로, 가로 좌우 만 허용된 상황에선 supportedInterfaceOrientations메소드가 UIInterfaceOrientationMaskAll을 리턴하여도 거꾸로된 화면은 허용이 안된다.


만약에 위의 스샷과 같이 화면이 허용된 상황에서 강제로 UIInterfaceOrientationMaskPortraitUpsideDown (거꾸로 화면만 허용)을 리턴하도록 코드를 짜면

'UIApplicationInvalidInterfaceOrientation', reason: 'Supported orientations has no common orientation with the application, and shouldAutorotate is returning YES'

라는 에러가 발생한다.


기타 Autorotate 관련하여 트러블슈팅 시 도움될 포스팅에 대한 링크.

http://devnote2.tistory.com/entry/iOS6-shouldAutorotate-NavigationViewController-%EB%AC%B8%EC%A0%9C

Posted by 하품 - yawn 하품 - yawn