요즘 너무 자주사용하므로 메모.


애플공식 참고링크

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/BinaryData/Tasks/WorkingBinaryData.html


NSData 를 NSString 으로

NSString *str= [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];


NSString 을 NSData 로

NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];



unsigned char array 를 NSData 로

NSUInteger size = // some size

unsigned char array[size];

NSData* data = [NSData dataWithBytes:(const void *)array length:sizeof(unsigned char)*size];


NSData 를 unsigned char array 로

NSUInteger size = [data length] / sizeof(unsigned char);

unsigned char* array = (unsigned char*) [NSData bytes];


Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

Objective-c에서 KVO를 구현해야 할 경우가 있어 메모해 둔다.

KVO를 간단히 설명하자면 오브젝트의 값(프로퍼티)를 감시하여 이벤트를 받을 수 있는 기능이다.

감시할때 감시하는 옵션에는 여러가지가 있으나 그중 제일 많이 사용하는 값변경에 대한 감시이다.


값을 감시할 때.

// NSYunjiClass 인스턴스 생성하여 "onAir" 값을 감시할 경우에는

NSYunji *yunjilove = [[NSYunji alloc] init];

[yunjilove addObserver:self forKeyPath:@"onAir" options:NSKeyValueObservingOptionNew context:nil];


감시값이 변경될경우 콜백 되는 메소드

//값이 변경되었을때 콜백되는 메소드

- (void)observerValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context


    {

        NSLog(@"keyPath:[%@] change:[%@]",keyPath, [change description]);

        

        //변화한 값을 판별

        if ([keyPath isEqual:@"onAir"]) {

            //처리할 내용을 코딩.

            

        }

    }


파라메터 설명


keyPath 갑시할 키.(프로퍼티)

object         감시대상 오브젝트 (NS윤지러브)

change        변화한 값정보.

context 임의의 오브젝트 nil

(여기서 context는 nil을 넣어주면된다. 감시자에게 참조값을 전달할 수 있다는데 지금 설명에서는 패스.)



값 감시 삭제할 때.

감시(Observer)를 했으면 반드시 삭제를 해야 한다. 물론 중복해서 삭제를 하거나 하면 에러가 발생하므로 주의.


[yunjilove removeObserver:self forKeyPath:@"onAir"];


수동통지 할때.

감시대상이 된 프로퍼티는 전부 통지되므로 통지가 많아지는 경우가 발생한다.

이 경우엔 해당 프로퍼티를 수동통지로 바꾸어서 한번에 통지하던지 하는 방법도 가능하다.


수동으로 통지하는경우에는 automaticallyNotiviesObserversForKey: 메소드를 실행하여 수동통지 되도록 코딩해 준다.


+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey

    {

        BOOL automatic = NO;

        if ([theKey isEqualToString:@"onAir"]) {

            automatic = NO;

        }

        else {

            automatic = [super automaticallyNotifiesObserversForKey:theKey];

        }

        

        return automatic;

    }



덛붙여,willChangeValueForKey: didChangeValueForKey: 의 메소드를 setter에다가 구현해 줄 필요가 있다.


수동통지를 구현하는 setter메소드

- (void)setOnAir:(NSString *)onAir

    {

        [self willChangeValueForKey:@"onAir"];

        _onAir = onAir;

        [self didChangeValueForKey:@"onAir"];

    }




의외로 유용하게 쓸일이 많은 기능이다.



Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

아이폰에서 챠트 또는 그래프를 그려야 하는 경우가 종종 있다. 개인적으로 만드는거라면 오픈소스를 가져다 쓰는게 가장 편하지만 디자인너의 요구사항이 까다롭다면 어쩔수 없이 직접 그려줘야 한다.


그리는 방법은 다음과 같은 순서로 작성한다.


1. UIView를 상속받은 차트용 뷰를 작성

2. 제대로 만들었다면 주석처리된 drawRect 메소드가 나오는데 이걸 주석을 해제.

3. drawRect메소드에 그리고 싶은 코드를 넣어줌


*참고로 drawRect메소드는 첫 화면에 뿌려질때 불려지는 콜백함수이다.

인위적으로 불러줘야 할 경우에는 setNeedDisplay라는 메소드를 호출해 준다.



그릴때 자주쓰는 기본적인 메소드를 만들어 실장해 보았다.


// Only override drawRect: if you perform custom drawing.

// An empty implementation adversely affects performance during animation.

- (void)drawRect:(CGRect)rect

{

    // Drawing code

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    

    [self drawLine:ctx

         color:[UIColor grayColor]

         width:1.0f

        startPoint:CGPointMake(10, 20)

          endPoint:CGPointMake(100, 40)];

    

    [self drawCircle:ctx

           fillColor:[UIColor blackColor]

         strokeColor:[UIColor grayColor]

              radius:30.0f

         CenterPoint:CGPointMake(250, 40)];

    

    [self drawText:ctx text:@"Graph TEST!!" size:13.0f point:CGPointMake(100, 100)];

}


- (void)drawLine:(CGContextRef)ctx color:(UIColor *)c width:(float)w startPoint:(CGPoint)sp endPoint:(CGPoint)ep {


    CGContextSetStrokeColorWithColor(ctx, c.CGColor);

    CGContextBeginPath(ctx);

    CGContextMoveToPoint(ctx, sp.x, sp.y);

    CGContextAddLineToPoint(ctx, ep.x, ep.y);

    

    CGContextStrokePath(ctx);


}


- (void)drawCircle:(CGContextRef)ctx fillColor:(UIColor *)fc strokeColor:(UIColor *)sc radius:(float)r CenterPoint:(CGPoint)cp {

    

    // Set the width of the line

    CGContextSetLineWidth(ctx, 2.0);

    

    //Make the circle

    // 150 = x coordinate

    // 150 = y coordinate

    // 100 = radius of circle

    // 0   = starting angle

    // 2*M_PI = end angle

    // YES = draw clockwise

    CGContextBeginPath(ctx);

    CGContextAddArc(ctx, cp.x, cp.y, r, 0, 2*M_PI, YES);

    CGContextClosePath(ctx);

    

    //color

    CGContextSetFillColorWithColor(ctx, fc.CGColor);

    CGContextSetStrokeColorWithColor(ctx, sc.CGColor);

    

    // Note: If I wanted to only stroke the path, use:

    // CGContextDrawPath(context, kCGPathStroke);

    // or to only fill it, use:

    // CGContextDrawPath(context, kCGPathFill);

    

    //Fill/Stroke the path

    CGContextDrawPath(ctx, kCGPathFillStroke);

    

}


- (void)drawCircle:(CGContextRef)ctx color:(UIColor *)c radius:(float)r CenterPoint:(CGPoint)cp {

    

    [self drawCircle:ctx fillColor:c strokeColor:c radius:r CenterPoint:cp];

}


- (void)drawText:(CGContextRef)ctx text:(NSString *)t size:(float)s point:(CGPoint)p {

    

    CGContextSetTextDrawingMode(ctx, kCGTextFill); // This is the default

    

    [[UIColor redColor] setFill]; // This is the default

    

    [t drawAtPoint:CGPointMake(p.x, p.y)

               withAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica"

                                                                    size:s]}];

    

    

    

}





출력결과




Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

iOS6부터 새로 추가된 AutoLayout 기능은 너무 편리하다. (사실... iOS6에서는 인터페이스가 엉망이라 불편했는데 iOS7부터는 많이 개선되었다.)


본론으로 들어가서, 스토리보드에AutoLayout을 적용하면 동적으로 프레임 좌표변경이 불가능하다.

정확히 말하면 분명 메모리상에서는 이미 바뀌어 있지만 화면에 표시될땐 변경된 좌표로 표시되지 않는 현상이 발생한다.

그 뿐만아니라 layer에 회전을 시키는 것도 제대로 동작하지 않는다.


지금까지 해결방법으로 스토리보드에서 AutoLayout를 해제하여 해결해왔는데 (정확히 말하면 AutoLayout사용을 포기한거임) 이제서야 제대로 된 해결방법을 알아냈다.



그 방법이란 좌표를 변경할 뷰를 일단 한번 띄어냈다가 다시붙이는 방법이다. 그렇게 하면 그부분만 AutoLayout의 쓸데없는 방해를 피할 수 있다.


예를들어..


for (UIView *v in moveView.subviews) {

        

        if ([v isKindOfClass:[UIView class]] == YES) {

            //변경을 원하지 않으면 패스

            continue;

        }

        

        [v removeFromSuperview];

        

        //프레임을 변경

        v.frame = CGRectMake(0, 0, 100, 200);

        

        [self.view addSubview:v];

        

    }



대충 이런식의 코딩이 가능하다.

참고로 뷰를 띄었다가 붙였을경우 IBOutlet에 연결된 커넥션이 무효화될까 걱정했었는데 무사히 동작한다.


혹시 모를 AutoLayout 때문에 고생하시는 개발자분들은 참고하시길.


2013.03.22 추가내용.

AutoLayout적용한 컨트롤러에서 UIScollView(스크롤뷰)에서 컨텐츠사이즈가 적용안되는문제가 발생하는데 아래와 같은 방법으로 해결할 수있다.


- (void)viewDidLayoutSubviews {

    

    [super viewDidLayoutSubviews];

    

    // 스코롤 컨텐츠사이즈 변경

    [scView setContentSize:CGSizeMake((_rView.frame.size.width + _tView.frame.size.width),

                                      [UIScreen mainScreen].bounds.size.height)];

    

    [self.view layoutSubviews]; //이부분이 중요

}



Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

앱에 필요한 앱서버를 만들기 위해 구글앱엔진을 이용하여 개발하기로 했다.

웹에 대한 내용들 설정방법들은 잘 정리된 곳이 무수히 많으므로 직접하면서 막혔던 문제만 메모를 해둔다.


작업환경 

작업피씨 및 운영체제는 맥(OS는 매버릭)이었고 이클립스를 이용하여 구글 앱 엔진을 구축하였다.

맥의 경우 파이썬이 기본적으로 설치되어 있는데 내 경우는 2.6 버전이 설치되어 있었다.


작업순서로는 

  1. 구글앱 엔진 계정 만들기 및 인증
  2. 이클립스 다운로드 및 설치
  3. 이클립스 파이썬 플러그인 설치
  4. 구글 앱 엔진 SDK다운로드 및 설치
  5. 구글 개발자 페이지를 참고하여 코드작성
  6. 구글 앱 런처로 디플로이하여 동작확인


구글앱 앤진 계정 만들기

딱히 어려울건 없었다. 단지 인증번호를 받아야 되는데 자기가 속한 휴대폰 통신사 메일로 인증을 받아야 한다.

왜 그러는지는 모르겠지만 인증만 받으면 사용할 수 있다.

무료로 만들수 있는 어플리케이션은 10개인데 한번 작성하면 지울수 없는듯 하다. 네이밍에 신중해야 할듯.


이클립스 다운로드 및 설치

이클립스 공식페이지에서 다운로드 하여 설치하면된다. 내 경우는 최신버전(4.3.1)으로 다운로드.

http://www.eclipse.org/downloads/



이클립스 파이썬 플러그인 설 치

아래의 링크를 이용하여 이클립스상에서 플러그인을 업데이트 해준다.

http://pydev.org/updates


여기서 좀 시간을 까먹었는데 플러그인을 설치했음에도 불구하고 프로젝트생성에서 pyDev메뉴가 나오지 않았다.

플러그인홈페이지를 자세히 읽어보니 작업피씨에 java1.7이상이 설치 되어 있어야 한다는 사실을 발견.

확인해보니 1.6이 설치되어 있어서 java sdk SE 1.7 다운로드하여 설치했다.


또하나 구글앱엔진 프로젝트 생성시 앱엔진SDK를 입력하는 창이 나오는데 앱엔진 SDK가 어디에 설치되어 있는지 몰라서 헤멨는데 아래의 경로로 선택해 주면 된다.

스택플로에서 해답찾음.

/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine



여기저기 개인블로그 찾아가며 해봤는데 기본이 안된 상태에서는 구글개발자페이지 튜토리얼을 추천한다.

영어압박이 심하지만 천천히 따라하면 어렵지 않은것 같다.


참고한 블로그들.

http://acasia.tistory.com/470

http://rucifer.tistory.com/entry/Google-App-EngineDjango를-이용한-Google-App-Engine-개발-1





Posted by 악당잰 트랙백 0 : 댓글 2

댓글을 달아 주세요

  1. addr | edit/del | reply 몽테스큐 2014.03.22 00:32

    아...
    이클립스에서 pydev 안뜨는것때문에 저도 헤매고 있었는데
    감사합니다!

개인적으로 iOS개발할때 불편하다고 생각되는것 중 하나가 CoreData를 이용한 개발이다.

간단한 테이블뷰어정도는 제공해줘도 될듯한데 XCode에 포함시키지 않았을까? 

애플의 사소한 배려가 없는 상황에서 지금까지는 그때끄때 무식하게 코딩으로 직접 만든 나만의 프로그램으로 해결하곤 했다. 

뭐 테이블뷰로 대충 붙여놓은 간단한 프로그램이긴 하지만.. 귀찮은 일이긴 했지만 자주 사용했으므로 나름 유용한 방법이긴했다. 

물론 앱스토어에 유용한 툴도 있겠지만 거의 파견형태로 일하는 나로서는 내 맥북도 아닌데 아무 어플리케이션이나 깔수 없었다.

그것이 무식한 방식을 선택한 이유이기도 했다.


그런데....무식하면 몸이 고생한다고... 정말 간단한 SQL만으로도 검색할 수 있는 방법이 있었다. 

sqlite명령어를 쓰면 되는데 왜 그생각을 지금까지 못했을까..


어쨋거나 반성은 나중에 하고 일단 메모해 둔다.


1. 당연한 얘기지만 확인해야할 파일을 작업폴더로 복사한 후 터미널을 실행시켜 해당 폴더로 이동한다.

2.sqlite를 실행한다. sqlite>라는 커서가 나타나면 성공.

sqlite3




3. 사용할 데이타베이스를 지정한다. (혹시 실행경로와 파일경로가 다를경우 풀패스를 적어주면 된다.)

sqlite3 데이타베이스 파일명




4. 종료할 경우 (명령어의 경우는 .(점) 으로 시작한다는 것에 주의)

sqlite>.exit 또는 .quit




5. SQL명령어는 ;를 마지막에 붙여준다.

*실제로 XCode에서 정의한 테이블명, 컬럼명 앞에 Z가 붙어 있다.

select * from 테이블명;




6. 검색시 컬럼명을 같이 출력하고 싶을때에는 헤더출력설정을 ON으로 해준다.

sqlite> .headers ON



7. 줄맞춤이 필요한 경우

sqlite> .explain ON



8. 기타 필요한 명령어

#데이타베이스 접속확인

sqlite> .database

#전체 테이블명 확인

sqlite> .tables


물론 도음말은 

sqlite> .help





Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

iOS에서 애니메이션 효과를 줄수 있는 방법은 세가지가 있다. 


UIView를 이용한 애니메이션. 제일 간단하고 쓰기 편하다.

    [UIView animateWithDuration:0.5f animations:^() {

        //애니메이션 내용코딩


    } completion:^(BOOL finished) {

        //애니메이션 끝난 처리


    }];





CABasicAnimation을 이용한 애니메이션. UIView애니메이션 보다 다양한 옵션을 줄 수있다. 기본 제공해주는 애니메이션 옵션이 많으므로 구현하기도 편하다.


1.QuartzCore.framework를 프로젝트에 추가하고 QuartzCore/QuartzCore.h를 사용할 클래스에 임포트 해준다.


#import <QuartzCore/QuartzCore.h>


2.CABasicAnimation의 인스턴스를 생성하고 애니매이션을 등록해 준다.

animationWithKeyPath: 메소드를 사용해서CABasicAnimation 의 인스턴스를 생성한다. 생성할 때에 keyPath에 사용할 키를 지정한다.


예를 들어 이동하는 애니메이션의 경우 position프로퍼티를 지정해 준다.

CABasicAnimation *animation =

    [CABasicAnimation animationWithKeyPath:@"position"];



3.애니메이션 옵션을 설정한다. 

*옵션종류

 duration

 애니메이션 재생시간

 repeatCount

 반복횟수

 beginTime

 애니메이션 시작설정

애니메이션 시작을 늦추려면 CACurrentMediaTime() + 초

의 형식으로 지정해 준다.

 timingFunction

 애니메이션 속도 변화지정

 autoreverses

 애니메이션 종료 후 역순으로 실행할지를 지정

 

 


아래와 같이 사용하면 된다.

animation.duration = 2.5; 

animation.repeatCount = 1; 

animation.beginTime = CACurrentMediaTime() + 2;

animation.autoreverses = YES;

animation.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut];



4.애니메이션 시작과 종료를 지정한다. 지정값은 키패스(keyPath)에 의해서 변한다.


 fromValue

 시작값

 toValue

종료값(절대치) 

 byValue

종료값 (상대치)


아래와 같은 형식으로 이용할 수 있다.

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];

animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];

animation.toValue = [NSValue valueWithCGPoint:CGPointMake(320, 480)];



5.작성한 애니메이션은 레이어에 추가할 수 있는데 그때에는 임의의 키패스(keyPath)를 지정한다.


[myView.layer addAnimation:animation forKey:@"testani"];


재생이 끝나면 처음상태로 되돌아 온다. 만약 애니매이션이 끝난상태 되돌아가지 않게 하려면 아래와 같이 코딩해 준다.

애니메이션이 끝난상태(completed)에서 아래의 코딩을 해준다.

animation.removedOnCompletion = NO;

animation.fillMode = kCAFillModeForwards;


CABasicAnimation사용예

/* 이동 */

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];

animation.duration = 2.5;

animation.repeatCount = 1;

animation.fromValue = [NSValue valueWithCGPoint:myView.layer.position];

animation.toValue = [NSValue valueWithCGPoint:CGPointMake(320, 480)];

[myView.layer addAnimation:animation forKey:@"move-layer"];


/* 회전 */

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];

animation.duration = 2.5;

animation.repeatCount = 1;

animation.fromValue = [NSNumber numberWithFloat:0.0]; 

animation.toValue = [NSNumber numberWithFloat:2 * M_PI]; //회전각도

[myView.layer addAnimation:animation forKey:@"rotate-layer"];


/* 확대, 축소 */

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];

animation.duration = 2.5;

animation.repeatCount = 1;

animation.autoreverses = YES;

animation.fromValue = [NSNumber numberWithFloat:1.0]; //1배

animation.toValue = [NSNumber numberWithFloat:2.0]; // 2배

[myView.layer addAnimation:animation forKey:@"scale-layer"];


복수개의 애니메이션처리를 할경우에는 아래와 같이 처리해 준다.


/* 애니메이션1(x축방향으로 이동) */

CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];

animation1.toValue = [NSNumber numberWithFloat:80];

 

/* 애니메이션2(z축으로 중심이동회전) */

CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];

animation2.fromValue = [NSNumber numberWithFloat:0.0]; //시작각도 

animation2.toValue = [NSNumber numberWithFloat:4 * M_PI]; //360도(90*4)

 

/* 애니메이션그룹 */

CAAnimationGroup *group = [CAAnimationGroup animation];

group.duration = 3.0;

group.repeatCount = 1;

group.animations = [NSArray arrayWithObjects:animation1, animation2, nil];

[myView.layer addAnimation:group forKey:@"move-rotate-layer"];



애니메이션 시작과 종료시 이벤트를 취득할 경우에는 델리게이트를 지정해 준다.

animation.delegate = self; 

 

딜리게이트 메소드

/**

 * 애니메이션 시작

 */

- (void)animationDidStart:(CAAnimation *)theAnimation

{

    NSLog(@"시작");

}

 

/**

 * 애니메이션 종료

 */

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag

{

    NSLog(@"종료");

}





마지막으로 CAKeyframeAnimation 이다. 전에 설명했던 애니메이션보다 더 세밀한 애니메이션을 지정할 수 있다.


CAAnimation를 사용하기 위해서는 <QuartzCore/QuartzCore.h> 프레임워크를 추가하고 해당 클래스에 임포트해 주어야 할 필요가 있다.


아래와 예제를 보자.



CAAnimation에 있는 Keyframe을 사용한다.


// scaleX와scaleY의 변화량을 키프레임(keyframe)형식으로 지정한다.

// array의갯수는 다음에 코딩할 timing과 숫자가 일치해야 한다.

NSArray *values = [NSArray arrayWithObjects:

                   [NSNumber numberWithFloat:0.1],

                   [NSNumber numberWithFloat:1.0],

                   [NSNumber numberWithFloat:1.0],

                   [NSNumber numberWithFloat:7.0],

                   nil];


// 투명도의 변화량을 키프레임(keyframe)형식으로 지정한다.

//array의갯수는 다음에 코딩할 timing과 일치 해야 한다.

NSArray *values2 = [NSArray arrayWithObjects:

                   [NSNumber numberWithFloat:0.1],

                   [NSNumber numberWithFloat:1.0],

                   [NSNumber numberWithFloat:1.0],

                   [NSNumber numberWithFloat:0.0],

                   nil];    


// Keyframe에 이용할 시간을 지정한다.(0.0~1.0)

// 0부터 1까지 지정하는걸 몰라서 한참 해맷는데.. 이걸로 CABasicAnimation에서 할수 없었던 세밀하게 속도조절이 가능하다.

NSArray *timing = [NSArray arrayWithObjects:

                   [NSNumber numberWithFloat:0.0],

                   [NSNumber numberWithFloat:0.25],

                   [NSNumber numberWithFloat:0.85],

                   [NSNumber numberWithFloat:1.0],

                   nil];


// 전체 애니메이션 시간

float duration = 1.5f;


// scaleX의keyframe의 애니메이션 지정

CAKeyframeAnimation *keyframe = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.x"];

keyframe.values = values;

keyframe.keyTimes = timing;

keyframe.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

keyframe.duration = duration;


// scaleY의keyframe의 애니메이션 지정

CAKeyframeAnimation *keyframe2 = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.y"];

keyframe2.values = values;

keyframe2.keyTimes = timing;

keyframe2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

keyframe2.duration = duration;


// 투명도 애니메이션 지정

CAKeyframeAnimation *keyframe3 = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];

keyframe3.values = values2;

keyframe3.keyTimes = timing;

keyframe3.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

keyframe3.duration = duration;



// CATransaction를 이용해 3개의 애니메이션을 동시에 실행

[CATransaction begin];

[CATransaction setCompletionBlock:^{

    NSLog(@"animation end.");

    [animationView removeFromSuperview];

}];

[animationView.layer addAnimation:keyframe forKey:@"transform.scale.x"];

[animationView.layer addAnimation:keyframe2 forKey:@"transform.scale.y"];

[animationView.layer addAnimation:keyframe3 forKey:@"opacity"];

[CATransaction commit];


애니메이션은 commit하는 동시에 실행되며 CATransaction을 사용하지 않고 addAnimation만 사용했을경우  addAnimation을 호출한 시점에서 실행된다.



이외에도 상세한 설정을 할수도 있는데 그건 귀찮아서 나중에 정리...할 생각이다. 

아래 소스를 참조해서 연구하면 될듯.

https://github.com/nakiwo/KeyFrameSample


아래는 Core Animation 애플문서(일본어)

https://developer.apple.com/jp/devcenter/ios/library/documentation/CoreAnimation_guide.pdf

Posted by 악당잰 트랙백 0 : 댓글 2

댓글을 달아 주세요

  1. addr | edit/del | reply 개발초보 2015.03.14 02:14

    효율은 어떻게되죠?

    왜인지는 모르겠지만 첫번째 방법으로 하는 것보다 2번째 방법이나 3번째 방법이 효율이 더 좋을것같은데.

    • addr | edit/del BlogIcon 악당잰 2015.03.14 12:02 신고

      코드작성면에서의 효율로 보자면 간단한 애니메이션(알파값조정, 프레임 위치조정)의경우 첫번째가 효율이 좋지 않을까 생각합니다.
      두번째 세번째는 다양한 애니메이션이 가능하므로 복잡한 애니메이션의 경우에 유리하겠죠.

Git에서 자주 사용하는 명령어 메모.

매번 검색하기도 귀찮고 해서..내용은 생각나는 대로 업데이트 할 예정(2013.11.11)


Git기본설정

*처음 맥에서 Git를 사용할때 자신의 정보를 등록

이거를 등록안한다고 해서 문제가 되진않지만 등록이 안되어 있을시 커밋할때마다 등록안됬다고 지저분한 로그가 출력됨.

git config --global user.name "사용자이름"

git config --global user.email "이메일"


*Git를 사용할때 자신의 정보를 등록확인

git config --global --list


*Git출력 컬러표시 설정

git config --global color.ui "auto"


*Git로그이력 출력

git log -출력행수

예) git log -1


*Git파일 무시하기(저장소 차원에서 무시)

.gitignore 파일에 무시할 파일 추가


*Git파일 무시하기(자신의 컴퓨터에만 무시)

/.git/info/exclude 파일에 무시할 파일추가


브런치(Branch) 사용

Git에선 새로운 기능추가,버그수정, 유지보수등을 쉽게 하기 위해 브런치를 활용한다. 원본 master 역시 브런치이다.


*브런치생성

git branch 새브런치명


*브런치 체크아웃 (브런치를 이동할때의 명령어.)

git checkout 브런치명


*브런치 일람보기

git branch


*브런치생성과 체크아웃을 한꺼번에 하기

git checkout -b 새로운브런치 기존브런치

예)git checkout -b newBranch master


브런치 합치기(Merge)

3가지 모드가 있음


*바로합치기

git merge newBranch


*커밋합치기

이경우엔 커밋이 스테이징까지만 되므로 git status로 상태확인후 커밋이 필요하다.

git merge --squash newBranch


*선택합치기

커밋한 내용은 고유의 해쉬값를 가지고 있으므로 커밋단위로 merge가 가능하다.

git cherry-pick 214bewf


스테이징까지만 merge하려면 -n옵션을 붙인다.

git cherry-pick -n 214bewf


충돌 다루기(Conflict)

충돌이 날경우에는 XCode에서 제공되는 툴을 이용하여 머지 작업을 한다. 충돌난 소스는 스테이징에 있기때문에 수정후 커밋이 필요.


브런치 이름변경

*브런치 이름 변경하기

git branch -m 현재브런치명 변경할 브런치명


이미 존재하는 브런치명이 존재할 경우 에러발생. 무시하고 덮어쓰기 하려면 -M 옵션을 준다.

git branch -M 현재브런치명 변경할 브런치명


기타 요긴하게 쓰이는 명령어


커밋하지 않은 내용들을  pull 하기전에 잠시 임시로 빼놓는 명령어

git stash 


임시로 빼놓은 내용들을 가져오기 (pull  한 다음)

git stash pop 


임시로 빼놓은 내용들을 표시

git stash show


임시로 빼놓은 내용들을 삭제

git stash clear




Git참고 사이트

http://wp.yat-net.com/?p=3874







TAG git
Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

iOS5부터인가 나왔던 기능으로 알고 있는데 block코딩과 더불어 생소한 문법 중 한놈이다.

굳이 써야되는 필요성을 느끼지 못한놈인지라 넘겨두고 있었는데 최근 비동기처리가 필요한 플젝을 하면서

어쩔수 없이 조금 공부하게 되었다.

정말 간단하게 구현되고 편리하므로 아마도 자주 써줘야겠다.

어쨌든 내가 아는한도내에서 두가지 정도 메모해 둔다.


첫번째 제일 자주 쓰는 구문. 이건 싱글톤 처리할때 쓰는 패턴이다. 다른방법도 있지만(인스턴스가 nil인지 아닌지 비교해서 분기해주는...)

어쩐지 이게 더 멋있어 보인다. 

쓰는 방법은 dispatch_once_t 라는 변수를 선언해주고 dispatch_once라는 메소드에 초기화 처리를 해주면 메소드 이름처럼 

딱 한번만 실행한다. 그러니 결과적으로 싱글톤이 됨.


+ (AVAudioPlayerManager*)sharedAVAudioPlayerManager {

    static dispatch_once_t pred = 0;

    __strong static id _vrObject = nil;

    dispatch_once(&pred, ^{

        _vrObject = [[self alloc] init];

    });

    return _vrObject;

}


두번째로 비동기를 위해 스레드 처리할 경우. 예를들어 메인스레드에서 시간이 걸리는 처리를 해버리면 

당연히 화면이 멈추는 현상이 나타난다. 왜냐면 화면처리는 메인스레드에서 처리되므로.. 

바꾸어 말하면 시간 걸리는건 메인스레드에서 처리하지 않는것이다. 다만 화면상태를 바꾸고 싶을땐 메인스레드에서 처리

해야 하므로 그 부분만 메인스레드로 넘기는 것이 포인트.


1.일반큐와 메인큐를 각각 선언한다. 

2.스레드를 사용하기 위해 dispatch_async 라는 메소드를 선언하고 일반큐를 파라메터로 넣는다.

3. 다음 처리로직안에 화면제어를 할 필요가 있는 처리에 대해선 메인큐(메인스레드)로 넘겨준다.


정말 간단하다. 백문이불여일견! 직접 소스를 보자.


dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    dispatch_async(globalQueue, ^{

    

        //시간이 걸리는 처리를 한다고 치자.

        int count = 0, i;

        for(i = 0; i < 10000; i++){

            NSLog(@"count = %d", count);

            count++;

        }

        

        //진행상태를 화면에 표시해주기 위해 메인스레드에 화면변경로직을 코딩.

        dispatch_async(mainQueue, ^{

            [self updateProcress:[self logStringWithCount:count]];

        });

        

        //또 시간이 걸리는 처리가 있다고 한다면...

        for(i = 0; i < 10000; i++){

            NSLog(@"count = %d", count);

            count++;

        }


        //끝났을 경우의 처리를 해준다. 여기서도 메인스레드로 처리해줌.

        dispatch_async(mainQueue, ^{

            [self updateProcress:[self logStringWithCount:count]];

            [_indicatorView stopAnimating];

            _startButton.hidden = NO;

        });

    });


Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

인류문명의 발달은 잉여노동력 그리고 적절한 환경에 의한 결과라는 제레미다이아몬드라는 유명한 아저씨의 주장이 요 며칠간 가깝게 다가왔다.

지금 마치 내상황이 잉여노동력(할일없음) + 적절한 환경(프로젝트 끝나감) 이므로 저아저씨 말대로라면 뭔라도 해야 될 상황이다.


프로젝트는 슬슬 끝나가고 할일은 없고.. 인터넷 서핑도 하루이틀이지.. 

잉여력이 넘치고 넘치던 찰나 결국 남는 잉여력을 소스코드를 이쁘게 고치는데 사용키로 했다.


지금까지 딜리게이트을 남발하면서 막개발을 해 왔는데 이번기회에 iOS5부터인가 지원되지 시작한 blocks비동기처리 방식를 써볼까? 라는 생각이 든것이다.


이제까지 문법자체가 생소해서 쓰고 싶지 않았는데 시계바늘을 본드에 붙여놓은듯 시간이 가질 않으니 어쩔수 없다.

결과적으론 익숙해지는데 조금 시간이 걸렸으나 한번 적용해보니 코드량이 상당히 줄어드는걸 체감했다.

더이상 딜리게이트를 남발하지 않으리...


그럼 일단 block방식으로 코딩하기 위한 문법부터 살펴보자.


블럭구문 기본적인 선언방법

^(파라메터,...) {

    //실행로직

};

 

블럭구문을 대입할 경우의 코딩

반환값 (^변수명)(파라메터,...) = ^(임시 파라메터...) {

    //실행로직

};


여기까지만 보면 어떻게 하라는 얘기인지 모를것이다. 직접 짜보자.


블럭구문으로 test라는 함수작성

int (^test)(int) = ^(int x) {

    return x + x;

};

 

// 결과출력

NSLog(@"%d", test(10));



블럭구문을 typedef로 정의할땐 이렇게 한다. 일반적으로 사용하는 패턴이므로 숙지해 두자.

typedef 반환값 (^변수명)(파라메터,...) 


블럭구문내에 변수사용하기.

__block를 변수앞에 붙이면 블럭구문내에서 값변경이 가능하다.

물론 붙이지 않아도 참조는 가능.


__block int x = 300;

void (^print)(void) = ^(void) {

    x++;

    NSLog(@"%d", x);

};


자.. 여기까지는 기본적인 사항이고 실제로 하고싶은 블럭구문을 메소드에 넘겨주는 걸 해보자.

- (void)example:(double (^)(int, int))func {

int i = 3;

int j = 4;


if(func(i,j) > 5) {

  //처리1...

}else {

  //처리2...

}

}


이런식으로 쓴다. 파라메터로 받은 블럭구분 결과로 처리가 가능하다. 이전엔 이와같은 처리를 딜리게이트로 해결했었다.


실제 호출될 경우에 블록구문내 처리를 하도록 코딩하자.

[self example:^(int n1, int n2) {

//실행처리

    return i+j;

}];


자 여기서 아까 언급했던 typedef 를 상기해보자.

그렇다 메소드에 넘기는 블럭구문을 간단히 정의하여 메소드길이를 줄일수 있다.


//이렇게 정의한 다음..

typedef double (^calcHandler)(int a, int b);



//이렇게 바꾸어 쓸수 있다.

- (void)example:(calcHandler)func {

...

}


딜리게이트의 경우는 프로토콜 정의해주고 그걸 받는쪽에서 위임받아서 처리해주는 구문까지 해야하므로 상당히 코딩량이 많아지는데 반해서 블럭은 상당히 코드를 줄어든다.


조금 설명이 부족한거 같아 한가지 예를 더 들어보자. 

어떤 특정 메소드를 실행이 끝난뒤 후처리를 해주는 메소드를 만들어보자.

블록구문이 사용된 우리가 흔히보는 메소드이다.

[self.navigationController dismissViewControllerAnimated:(BOOL) completion:^{

        //TODO: 

        //화면이 닫힌후 후처리.

    }];

    


먼저 블럭구문부터 관찰해보면 반환값, 파라메터도 없는 블럭이다.

^{ 

//TODO: 

}


위와 같은 처리를 하는 calcTime라는 이름의 메소드를 만들어보자. 그리고 이 메소드가 실행이 완료되면 실행되는 블럭을 만들어 보자.


우선 메소드 선언.

- (void)calcTime:(void ^(void)handler;


그리고 메소드 정의

- (void)calcTime:(void ^(void)handler {


//무쟈게 오래걸리는 처리가 있다고 치자..

//...

//처리가 다 끝난부분에서 블럭구문을 실행하게 한다.

handler();

}

    

    

실제 호출하여 사용할때에는..

[self calcTime:^{

//이메소드 끝날때 처리할 내용 코딩..

}];



써놓고 보니 별 내용없네.. 

테스트하면서 코딩한게 아니라서 소스에 오류가 있을수 있으므로 참고하시길..


Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요