라벨이 iOS인 게시물 표시

Flutter 로 iOS 에 저장된 getApplicationDocumentDirectory 위치가 달라짐

Flutter 에서 iOS 기기의 앱 도큐먼트에 사진을 저장하고 있다. 이 사진 파일의 패스와 이름을 내부 데이터베이스에 저장하여  필요할 때마다 불러와서 사용하고 있다. 갱신이 필요하여 소스를 수정 하였는데 이전에 저장한 이미지가 전부 오류났다. 확인해보니 패스가 달라진 것이다. 이전에 저장한 패스는  /var/mobile/Containers/Data/Application/89AB9292-2F1F-4B9C-8EC7-2A45E08DBC2D/Documents 소스 수정 후 불러온 패스는 /var/mobile/Containers/Data/Application/76D29B57-B94C-4281-B948-677590233200/Documents 찾아보니 Bundle ID 같으면 패스가 같다고 하는데 다르게 나온다. 아무래도 다른 방법을 찾아야 할 거 같다.

효율적인 줌 조정 알고리즘

아이폰에서 보통 두개의 손가락으로 줌을 조정할 때가 있다. 이때 핀치 스케일이라는 변수를 함수에서 던져준다. pinch.scale 이 값이 보통 0.0 ~ 5.0 정도 나오는거 같다. 로그를 찍어보니 그렇다. 내가 하고 싶은 건 1.0 미만은 1.0으로 고정하고 4.0 이상은 2.0으로 고정하되 나머지 값은 배율로 정하기로 했다. 보통 일단 이렇게 구성한다. if pinch.scale < 1.0 {     zoomFactor = 1.0 } else if pinch.scale > 4.0 {     zoomFactor = 2.0 } else {     zoomFactor = ((pinch.scale - 1.0) / 3) + 1.0 } 이것도 잘 돌아간다. 좀 더 짧고 잘 돌아가게 할 수 없을까? zoomFactor = max(1.0, min(((pinch.scale - 1.0) / 3) + 1.0, 2.0) 이렇게 하면 한줄로 표시된다. 하지만 코드 추적하기 어렵다. 뒤에 오는 사람을 위해 좀 더 알아보기 쉽게 한줄 더 쓰자 let scale = ((pinch.scale - 1.0) / 3) + 1.0 zoomFactor = max(1.0, min(scale, 2.0) 이렇게 하면 보기 쉽고 깔끔한거 같다. 뭐 정답은 없지만... 눈길을 걸을 땐 발자국이 잘 찍히는지 확인하면서 가자. 뒤에 오는 사람을 위해서... 그 걸음이 쌓이면 길이 될테니까....,

[iOS] 1,024.67 과 같은 표현하기

천단위로 콤마를 찍고 소수점 2째만 표시하기 보통 숫자는 이런식으로 표시를 많이 한다. 이를 표현하기 위해서 StrintWithFormat(@"%#,###.2f", 대상 숫자) 위와 같이 하면 될 줄 알았으나 안된다. 흑흑 iOS 는 이를 위해 별도의 방법을 제공하고 있다. NSNumberFormatter 가 그것이다. NSNumberFormatter *numberFormatter = [NSNumberFormatter new]; [numberFormatter setGroupingSeparator:@","]; [numberFormatter setGroupingSize:3]; [numberFormatter setUsersGroupingSeparator:YES]; [numberFormatter setDecimalSeparator:@"."]; [numberFormatter setNumberStyle:NsNumberFormatterDecimalStyle]; [numberFormatter setMaximumFractionDigits:2]; 이제 사용은 label.text = [NSString StringWithFormat:@"%@", [numberFormatter stringFromNumber:[NSNumber numberWithFloat:1024.6789]]]; 결과가 1,024.67 로 나오면 성공이다.

[iOS] SKShapeNode 에 SKEffectNode 를 사용하여 Blur 효과 주는 방법

SKShapeNode 에 SKEffectNode 를 사용하여 Blur 효과 주는 방법 // 먼저  SKSpapeNode 를 생성한다 SKShapeNode *shape = [SKShapeNode node]; UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(-50, -50, 100, 100) cornerRadius:5]; shape.path = path.CGPath; shape.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)); shape.fillColor = [UIColor WhiteColor]; // 이제 SKEffectNode 를 생성한다 SKEffectNode *effect = [SKEffectNode node]; effect.ShouldEnableEffects = YES; CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"]; [filter setDefaults]; [filter setValue:@(3.5) forKey:@"inputRadius"]; effect.filter = filter; [effect addChild:shape]; [self addChild:effect]; 위와 같이 하면 Blur 가 적용된 Shape 를 볼 수 있다. 이 소스로 나머지는 활용하면 되겠다.

[iOS] 헤더 파일에 프레임워크 추가 하지 않고 적용시키는 방법

prefix.pch 란 파일이 있다. 이 파일의 내용에 헤더파일을 추가하면 별도로 지정하지 않고 사용할 수 있다. #ifdef __OBJC__     #import <UIKit/UIKit.h>     #import <Foundation/Foundation.h>     #import <AVFoundation/AVFoundation.h>     #import <iAd/iAd.h>     #import <SpriteKit/SpriteKit.h> #endif 위와 같이 추가하면  각 헤더를 헤더 파일에 추가하지 않아도  적용이 된다.

[iOS] 상태창 감추기

iOS 7 에서 상태창을 숨기는 것이 잘 안된다. 이런 방법을 써야만 한다. 다른 설정은 할 필요가 없다. 일단 이 메소드를 생성한다. - ( BOOL )prefersStatusBarHidden {     // 상태창 감추기     return YES ; } 그런 다음 viewdidload 에 아래를 추가한다.     // 상태창 감추기     if ([ self respondsToSelector : @selector (setNeedsStatusBarAppearanceUpdate)]) {         // iOS 7         [ self setNeedsStatusBarAppearanceUpdate ];     } else {         // iOS 6         [[ UIApplication sharedApplication ] setStatusBarHidden : YES withAnimation : UIStatusBarAnimationSlide ];     } iOS 7 에서는 [self setNeedsStatusBarAppearanceUpdate ]; 이 메소드를 실행하면  prefersStatusBarHidden 의 메소드도 실행된다. 위와 같이 하면 상태창을 숨길 수 있다.

[iOS]SKSprite Kit 에서 iAD 창을 화면 상단에 띄우기

iAD가 생성되면서  화면의 하단에 떠서  이를 상단으로 띄우기 위하여  많은 자료를 검색했으나 없었다. 하지만 꼼수는 있는 법. 나는 이 방법으로 상단에 iAD를 띄울 수 있었다. 일단 main.storyboard에서 iAD를 상단에 위치 시킨다. 그런 다음 이를 아래와 같이 연결시킨다 @property ( weak , nonatomic ) IBOutlet ADBannerView *banner; 이제 m 파일에 아래와 같이 추가한다. - ( void )viewWillLayoutSubviews {     [ super viewWillLayoutSubviews ];     // ADBanner     self . canDisplayBannerAds = YES ;     // SKView     SKView *view = ( SKView *) self . originalContentView ;     SKScene *scene = [[ MyScene alloc ] initWithSize : CGSizeMake ( self . view . frame . size . width , self . view . frame . size . height )];     [view presentScene :scene]; } 이제 실행해보면 상단에 위치 될 것이다. 하지만 iAD가 빈창으로 생성되기 때문에  영..., 거슬린다. 나는 iAD 의 appha 값을 0.1로 설정하였다. 이를 0으로 했더니 하단에 생성이 된다. iAD의 값을 가져오면 1.0으로 설정하고 못 가져오면 0.1로 했더니 보기가 낫다. - ( void )bannerView:( ADBannerView *)banner didFailToReceiveAdWithError:( NSError *)error {     NSLog (

[iOS] SKLabelNode 글자 색 변경하기

SKLableNode 에서 글자 색을 변경할 때 사용한다. SKLabelNode *label = [[SKLabelNode alloc] initWithFontNamed:@"Chalkduster"]; label.fontColor = [UIColor redColor]; 이렇게 해야 글자 색이 변경된다.

[iOS] SKSpriteNode를 화면 가운데에 위치 시키기

노드를 생성하고 노드의 위치를 화면 중간에 위치 시키고자 할때 유용하다. node.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)); 이를 응용하면 많은 코드를 줄일 수 있으며 화면에 따른 위치 하드코딩을 대체할 수 있다.

[SpriteKit] SpriteNode 에 gravity 적용하는 방법

player 를 SpriteNode 로 생성하였습니다. 이미지를 삽입하여 생성하면 이미지 크기로 생성이 됩니다. self . player = [[ SKSpriteNode alloc ] initWithImageNamed : @"spaceman.png" ]; 위와 같이 spaceman.png 를 삽입하여 생성합니다. 이 플레이어만을 중력값을 적용하고 싶을 때 이렇게 하면 됩니다. 아래에서 200 정도 위에 중앙에 위치시킵니다. self . player . position = CGPointMake ( CGRectGetMidX ( self . frame ), CGRectGetMidY ( self . frame ) - 200 ); 그 다음 이 한줄을 추가해야 합니다. 저도 이것때문에 며칠을 찾았습니다. self . player . physicsBody = [ SKPhysicsBody bodyWithRectangleOfSize : self . player . size ]; 설정이 마무리 되었으니 이제 추가해야겠죠. [ self addChild : self . player ];          이제 물리세계를 현 객체에 연결합니다. self . physicsWorld . contactDelegate = self ; 이제 중력값을 설정합니다. 기본값은 (0, -9.8)로 지구와 동일하나 이것으로는 눈깜짝할 새에 사라져 버립니다. 전 이 값으로 설정했습니다. self . physicsWorld . gravity = CGVectorMake ( 0.05 , 0 ); 플레이어는 오른쪽으로 천천히 움직일 것입니다.

[iOS] Sprite Kit 로 Hello world 만드는 방법

이미지
애플에서 게임 개발을 위한 아주 편리한 개발 키트를 내 놓았습니다. Sprite Kit 인데요. 이를 활용해서 hello world 를 만들어 보겠습니다. 먼저 xcode 를 실행합니다.  여기에서 새로운 프로젝트 생성을 클릭합니다.  single view 를 선택한 다음 next를 클릭합니다.  이름을 정하는데요. 전 위와 같이 하였습니다.  기본적으로 이렇게 생성이 됩니다. 델리게이트와 뷰 컨트롤러 하나... 이제 프레임 워크를 추가해야 합니다. Sprite Kit 를 선택하여 추가합니다. 이제 뷰 컨트롤러에 프레임 키트를 추가합니다. 추가를 해야 활용할 수 있지요. 여기서 중요합니다. 저도 여기서 잠깐 헷갈렸거든요. 스토리보드를 선택한 다음 뷰 컨트롤러 밑에 뷰를 선택해야 합니다. 그런 다음 오른쪽 클래스 창에서 SKView를 선택합니다. 이제 Scene 를 추가할 건데요. 위와 같이 메뉴에서 파일을 선택하여 추가합니다.  클래스로 선택해서 다음을 클릭합니다.  저는 이름을 위와 같이 하였습니다. 서브 클래스는 SKScene 로 선택하십시오. 모듈 파일에서 세개의 메소드를 생성하였습니다. 라벨을 생성하여 그 안에 문자열을 삽입하는 내용입니다. 이게 실행이 될려면 뷰 컨트롤러에 추가한 파일의 헤더파일을 추가해야 합니다. 그런 다음 뷰가 생성될 때 메소드에 위와 같이 추가하였습니다. 그리고 빌드하여 런을 합니다. 위와 같이 화면이 나오면 성공입니다.

[iOS]UIView 를 활용한 Animation

iOS 에서 애니메이션 을 줄때 사용한다. 다른 옵션들이 있지만 이것만 해도 충분할 꺼 같다. 다른 옵션들은 매뉴얼을 찾아보면 있다. 일단 Duration 1.5는 1.5초 동안 애니메이션 한다. animations 에 설정된 값으로 애니메이션 한다는 뜻이다. completion 은 마무리할 때 이렇게 한다는 뜻이다. [ UIView animateWithDuration : 1.5f                      animations :^{                          // O, X 표시                          self . viewAnswer . alpha = 1.0f ;                          self . viewAnswer . hidden = NO ;                          // 점수판 흐리게                          self . viewTestBoard . alpha = 0.5f ;                          self . labelTest1 . alpha = 0.3f ;                          self . labelTest2 . alpha = 0.3f ;                      }                      completion :^( BOOL finished){                          // O, X 감추기                          self . viewAnswer . alpha = 0.0f ;                          self . viewAnswer . hidden = YES ;                          // 점수판 보이기                          self . viewTestBoard . alpha = 1

[iOS] How to get Storage Available

how to get storage available -(NSNumber *)getStorageAvailable {     NSNumber *availableGiga = [NsNumber numberWithFloat:0.0f];     NSError *error = nil;     NSArray *paths = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);     NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error:&error];     // 소수 2자리까지 표시     NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];     formatter.roundingIncrement = [NSNumber numberWithFloat:0.01];     formatter.numberStyle = NSNumberFormatterDecimalStyle;     if (dictionary) {         NSNumber *availableByte = [dictionary objectForKey:NSFileSystemFreeSize];         availableGiga = [NSNumber numberWithFloat:((([availableByte floatValue] / 1024) / 1024) / 1024)];         NSLog(@"%@G", [formatter stringFromNumber:availableGiga]);     } else {         NSLog(@"Error: %@", error.description);     }     return avai

[iOS] How to extract the filename from NSURL

NSURL 에서 filename 을 추출해야 할때가 있다. 이럴 경우에 아래와 같이 하면 된다. NSString *filename = [[URL path] lastPathComponent]; NSLog(@"filename: %@", filename); 위 방법을 알기 위해 많은 검색이 필요하였습니다. 알면 쉽지만 모르면 코딩의 길이가 길어집니다. 처음에 문자열을 전체 검색하여 일일히 비교하면서 추출하고자 하였습니다. 위와 같은 메소드가 있는 줄 모르고 삽질을 하였습니다.

[iOS] how to use video capture(landscape, full screen)

이미지
비디오 캡쳐에서 가로보기가 전체화면으로 안될 때가 있다. 이에 여러가지 문제를 하나씩 찾아가며 처리한 내용을 여기에 정리한다. 정립한 순서는 다음과 같다. 먼저 헤더파일은 다음과 같다.  델리게이트를 하나 추가한다 다음은 모듈파일이다.  사용할 변수와 상수 그리고 메소드 선언한다. 다음은 뷰가 생성될 때 이루어 지는 내용이다. 여기서 중요한 점은 가로보기 설정인데 전체 스크린을 돌렸으니 뒤집어서 설정해야 한다. 이 한줄이 핵심이다.  나머지 설정을 하고 앞에 만들었던 레이어를 추가하는데 버튼 등을 사용해야 하므로 그 앞단에 뷰를 추가하였다.  뷰가 보일려고 할 때 스위치를 설정한다.  준비 메소드이다.  카메라 위치 설정이다. 파일을 저장할 때 사용한다.  버튼 이벤트를 입력 끝으로 카메라 토글 버튼 이벤트이다. 이런 순으로 작성하면 카메라 녹화를 가로로 할 수 있다.

iOS self.variable 과 _variable 의 차이점

그냥 무턱대고 개발을 하다 보면 문득 궁금한 점이 생긴다. self.variable 과 _variable 의 차이가 무얼까? 보통 iOS는 h 로 불리우는 헤더파일 (보통은 Public 으로도 부른다. 이곳에 선언을 하면 Public 이 되기 때문이다.) 과 m 으로 불리우는 모듈파일(보통은 Private로 불리우며 이곳에 선언을 하면 Private 가 되기 때문이다.) 헤더파일에 만약 다음과 같이 변수를 하나 선언하였다면 @property NSString *stringVariable; 이를 보통 모듈파일에서 이렇게 사용한다. 1. self.stringVariable  2. [self stringVariable] 3. _stringVariable 1번과 2번은 사용법만 다르지 같다. 하지만 3번은 다르다. 1번가 2번은 객체를 사용하는 방법이며 3번은 인스턴스 변수를 접근하는 방법이다. 인스턴스 변수는 객체를 할당하고 시작해야 접근할 수 있다.

iOS 두 값을 비교할 때 주의할 점

iOS 개발을 할 때 종종 두 값을 비교하는 방법을 사용한다. 보통은 이렇게 사용한다 if (obj1 == obj2) {   // 처리 방법 } 이것은 두개의 객체 포인터가 같은 곳을 가리키는 경우만 해당된다. 두 객체의 값이 즉, 데이터가 같을 경우는 다음과 같이 사용해야 한다. if ([obj1 isEqual:obj2]) {   // 처리 방법 } Objective C는 그냥 C와 다르다. 그냥 지나치기엔 내용이 많이 달라지므로 명심하도록 하자.

iOS In-App Purchase 02 Coding

개발을 하기 위해서는 프레임웍을 추가해야 한다. StoreKit.framework 를 추가하자. 그다음 전역헤더 파일에 추가할 내용이다. 아래와 같이 프레임워크를 임포트 하자. #import < StoreKit/StoreKit.h > 다음은 델리게이트와 사용할 전역변수를 추가한다. @interface ADViewController : UIViewController < SKProductsRequestDelegate , SKPaymentTransactionObserver > {     SKProductsRequest *productsRequest;     NSArray *validProcucts; } 나중에 사용할 메소드를 추가한다. - ( void )fetchAvailableProducts; - ( BOOL )canMakePurchases; - ( void )purchaseMyProduct:( SKProduct *)product; - ( IBAction )purchase:( id )sender; 이제 실행할 m 파일에서 할 내용이다 상수로 아이튠즈에서 설정한 프로덕트아이디를 설정한다. 이는 import 와 interface 사이에 추가하면 된다. #define kProductID @ "com.xxx.xxx.noAd" 이제 실행하면서 구입할 수 있는지 여부를 체크하도록 하자 이는 ViewDidLoad 에 추가했다. 다음과 같이 한 이유는 2초 이후에 실행되도록 지연실행을 걸어준것이다. [ self performSelector : @selector (fetchAvailableProducts) withObject : self afterDelay : 2.0 ]; 이제는 다음과 같이 관련 메소드를 추가한다. 여기서 입맛에 맞게 관련내용을

iOS In-App Purchase 01 아이튠즈 설정

앱내 구입방법을 간단하게 정리한다. 먼저 아이튠즈에 들어가서 Manage Your App에 들어가서 해당 앱을 선택한다. 오른쪽 상단에 Manage In-App Purchase 가 있다. 들어가서 관련설정을 한다. 상단의 Create New를 클릭하여 여러가지를 설정한다. 중요한 것은 Type을 선택한 후 Product ID 이다. 이는 프로그램에서 해당 아이템을 구분하기 위한 구분자로 생각하면 되겠다. 나머지 설정은 그냥 그럭저럭 무난하게 할 수 있다. 잘 모르겠으면 하고 싶은대로 하면 된다. 여기서 중요한 게 있다. 나도 여기서 한동안 헤멨다. 마치 안개속을 걸어다니는 것처럼......, 위와 같이 설정한 다음에 수정중인 앱 설정하는 곳의 View Detail에 들어가서 (이때 앱은 수정중이어야 한다, 아니면 버전추가로 하나 수정을 만들자) 아래로 스크롤을 내리면 In-App관련이 있다. 여기에 조금전에 추가한 내용이 보인다. 이를 앱에 적용하려면 체크하여 추가하도록 하자. 여기까지하면 개발준비상태가 된 것이다.

iOS 메소드를 지연 실행시키는 방법

어떤 메소드를 실행시킬 경우 지연시키는 방법에 대한 고찰이다. 첫번째 가장 간단하게 사용하는 경우 sleep(1000); 이렇게 하면 1초를 지연시킨다. 그다음 조금 더 세련된 방법으로 스레드를 이용할 수 있다. [ NSThread sleepForTimeInterval :1. 0 ]; 스레드로 프로세스를 쪼개서 사용할 때 유용하다. 하지만 GCD안에서 좀더 확실하고 세련되게 사용되는 방법은 없을까? 고민을 하였다. 결국인 이렇게 사용한다. dispatch_time_t popTime = dispatch_time ( DISPATCH_TIME_NOW , 1. 0  * NSEC_PER_SEC ); GCD 루프안에서 사용했는데 안정적으로 잘 구동된다. 앞으로 지연실행은 이것을 사용해야겠다.