Storyboardなんか使わない方がいい

iOSアプリを趣味やら仕事やらでほそぼそと作っていますが、 Storyboardを使う意味がよく分かりません。なんなんでしょうあの子。 でも 「なんで必要ないの?」 と聞かれると 「なんか色々めんどくせぇ。てやんでぃ」 としか言えなかったのですが、「ここがめんどくさい!」という部分がまとまった記事がありました。 ⇒ Q. StoryboardとXIBはどう使い分ければいいんだろうか? – Qiita 最近よく見るQiitaのまとめです。 (どうでもいいけどここに投稿している人ってみんなエンジニアなのにどうして自分のブログとかに書かないんだろう。使いやすいのかしら。) ってなわけで、Storyboardがいらないという理由の要点をまとめてみます。 Storyboardがいらない理由その1 「こんがらがる」 小規模ならまだしも、 規模が大きくなるとその分ページが増えて行きます。 こちらの画像はApplivのアプリのStoryboardです。(画像元:Catcher in the tech) (執筆時にはApp Storeから消えてました。何かあったのかな。) どうでしょう。確かに一見仕事してる感がムンムンと出てて、なんか待ち受けにしたいくらいカッコいいです。本音を言うと、したくはないです。 ここに新たなViewControllerを追加する場合、拡大したりスクロールしたり、色々探しまわって繋いで… 想像するたけで、汗がタラタラ出て来ます。本音を言うと、出て来はしないです。 Storyboardがいらない理由その2 「チーム開発に不向き」 Storyboardでコンフリクトが起きると、これを解消するのがすごく大変。 コードレビューも大変。打ち間違いに気づかない場合も多いです。 あと性格にもよりますが、ViewControllerをさっきの画像のようにきちっと並べたい。 誰かがズラしたり、新しいViewControllerが挿入されると直したくなります。でもまたズレるのさ。 Storyboardがいらない理由その3 「柔軟性がない」 おそらく一番大きな理由でしょう。 「このタイプのセルの背景はこの色で統一しよう。」⇒#defineで用意した値を入れられないから、スクロールして拡大して、探し回って同じ色を入力しなければならない。「やっぱり違う色にしよう」⇒スクロールして拡大して、探し回って…「あ、待って。やっぱりこの色にしよう」⇒ゲロゲロ UIImageViewの上にaddSubview出来なかったり、UIViewContllorの型が変更できなかったり、コードならささっと出来ることも大変な作業量になってしまうことがあります。 オシャレなアニメーションなんかはやっぱりコード上でないと実装できないです。 Storyboardを使わない方がいい理由まとめ ・Storyboardで出来ることは全てコードで出来る。(Storyboardでは出来ないことがある。) ・規模が大きくなると、Storyboardで得られるメリットよりデメリットの方が大きくなる。 ・なんか色々めんどくせぇ。てやんでぃ 今から、iPhoneアプリ作りを始める方は是非Storyboardなしでやった方がいいと思います。 ⇒ Xcode6でもストーリーボードなしのEmpty Applicationから始めたい

View More

Xcode8でコメントアウトが効かない場合

公開: 2016-09-15 22:31 どうもどうも。同じみのあっきぃさんです。 最近の趣味といえば散歩中の犬を探すことです。 そうです。飼い主が金持ちそうならば隙をついて入れ替わるつもりです。 早いもので、iOS10が出ました。 Xcodeのバージョンも上がってXcode8になりました。 ダウンロードに1時間くらいかかったのはさておき、使ってみるとなんと、 コメントアウトが効きません。(※ドラッグ選択でまとめていっきにやるやつ) なんだろうなー こわいなーこわいなー でもご安心を。プログラミング会のゴーストバスターことStack Overflowに答えは出てるんです。 ⇒ xcode8 – XCode 8 Beta 5 & 6 Comment out broken – Stack Overflow ターミナルで $ sudo /usr/libexec/xpccachectl と打った後、Macを再起動をさせるだけです。 これで見事に治りました。 (なんで治るかは知らない。) ではでは。

View More

NSStringのファイルパスからディレクトリ名を取得する

公開: 2015-07-10 00:15更新: 2016-04-29 06:03こーんなNSStringがあります。 NSString *path = @”/var/mobile/Containers/Data/Application/AAA/Documents/image.png” image.pngってな画像のフルパスですが、 このファイルがあるとこのディレクトリのパスが欲しいです。 今まで「/」で分割してましたが、なんか便利なのがあるようです。 それがこちら path.stringByDeletingLastPathComponent; 中身は… /var/mobile/Containers/Data/Application/AAA/Documents ほう。 これが欲しかった。 逆に path.lastPathComponent; と、やれば image.png ファイル名が取得できます。うむ。 他にも色々な便利関数があるのでNSStringのドキュメントを眺めてみると面白いカモ。 ⇒ NSString Class Reference ではでは。

View More

UIViewのframe.size.widthとかめんどくさいので省略する

UIViewの幅や高さにアクセスするのがめんどくさいので省略出来るようにします。 UIView+Simple.h/mという名前のUIViewを拡張するカテゴリファイルを追加します。 //UIView+Simple.h #import <UIKit/UIKit.h> @interface UIView (Simple)-(CGFloat)width;-(CGFloat)height;-(CGFloat)x;-(CGFloat)y;-(CGPoint)o;-(CGFloat)right;-(CGFloat)bottom;-(void)toFront;-(void)toBack;-(CGSize)trueSize;@end //UIView+Simple.m #import “UIView+Simple.h” @implementation UIView (Simple)-(CGFloat)width { return self.frame.size.width; }-(CGFloat)height { return self.frame.size.height; }-(CGFloat)x { return self.frame.origin.x; }-(CGFloat)y { return self.frame.origin.y; }-(CGPoint)o { return CGPointMake(self.width / 2, self.height / 2); }-(CGFloat)right { return self.frame.origin.x + self.frame.size.width; }-(CGFloat)bottom { return self.frame.origin.y + self.frame.size.height; }-(void)toFront { [self.superview bringSubviewToFront:self]; }-(void)toBack { [self.superview sendSubviewToBack:self]; }-(CGSize)trueSize { CGAffineTransform t = self.transform; self.transform = CGAffineTransformIdentity; CGSize size = self.frame.size; self.transform = t; return size; }@end UIView+Simple.hをPCHファイルなんかで全体に読み込まれるようにしておきます。 #import “UIView+Simple.h” そんでもって使い方。 例1.親Viewの中央に乗せる subview.center = view.o;[view addSubview:subview]; 例2.View1の右隣にマージン14pxでView2を設置する view2.frame = CGRectMake(view1.right + 14.0, view1.y, view2.width, view2.height); 例3.Viewを先頭に持ってくる [view toFront] などなどなどなど… (便利でしょ?) 他にも省略したいものがあればココにどんどん追加すればいいのでーす♪

View More

UIViewを反転させる

UIViewを反転させる方法です。 CGAffineTransformを使えば1行でいけます。 例のごとく対象となるUIViewを用意しましょう。 – (void)viewDidLoad {        [super viewDidLoad];         UIView *view = [UIView new];        view.frame = CGRectMake(0, 0, 200, 200);        view.backgroundColor = [UIColor redColor];        view.center = CGPoinMake(self.view.frame.size.width/2, self.view.frame.size.height/2);        [self.view addSubview:view];         UIImageView *imageView = [UIImageView new];        imageView.image = [UIImage imageNamed:@”apple”];        [view addSubview:imageView];        …} ふむ。 1.左右反転 x軸方向に-1倍拡大してあげるだけです。 view.transform = CGAffineTransformMakeScale(-1, 1); 2.上下反転 y軸方向に-1倍拡大してあげるだけです。 view.transform = CGAffineTransformMakeScale(1, -1); 3.上下左右反転 流れでわかると思いますが、x,y軸方向に-1倍拡大してあげるだけです。 view.transform = CGAffineTransformMakeScale(-1, -1); 簡単ですな。

View More

UIViewの回転、拡大、縮小

iPhoneアプリといえばアニメーションが綺麗です。 どこぞのアンドロイドと違って変にカクカクしないですし、滑らかです。 そしてアニメーションといえば移動、回転、拡大、縮小の組み合わせが多いでしょう。 そんなわけで今回はUIViewをCGAffineTransformとか言うよく分からない奴で移動、回転、拡大、縮小をする方法の基本を学びましょう。 とりあえず対象のViewを用意します。 ほおおおおお…そいやっ – (void)viewDidLoad {        [super viewDidLoad];         UIView *view = [UIView new];        view.frame = CGRectMake(0, 0, 200, 200);        view.backgroundColor = [UIColor blueColor];        view.center = CGPoinMake(self.view.frame.size.width/2, self.view.frame.size.height/2);        [self.view addSubview:view];         UIImageView *imageView = [UIImageView new];        imageView.image = [UIImage imageNamed:@”apple”];        [view addSubview:imageView];        …} いい感じですね。 そして相変わらずこのブログのコードのカラーリングはとっても見やすいです。 1.移動 右に40px、上に50px移動させます。 view.transform = CGAffineTransformMakeTranslation(40, -50); 2.回転 30°右に回転させます。 view.transform = CGAffineTransformMakeRotation(M_PI * 30.0 / 180.0); こんなDefineを用意すればスッキリします。 #define RADIAN(x) (M_PI * (x) / 180.0)…view.transform = CGAffineTransformMakeRotation(RADIAN(30)); 3.拡大と縮小 拡大と縮小です。比率を大きくすれば拡大、小さくすれば縮小出来ます。 view.transform = CGAffineTransformMakeScale(1.5, 1.5); 第1引数がx方向の拡大率、第2引数がy方向の拡大率なので、別の値を入れれば歪ませることも出来ます。 view.transform = CGAffineTransformMakeScale(0.5, 1.2); 4.初期化 真っさらな状態に戻します。つまりデフォルト値です。 view.transform = CGAffineTransformIdentity; 5.組み合わせる 「拡大して回転」みたいにアフィン変換を組み合わせます。 5.1.対象となるCGAffineTransformを指定するパターン アフィン変換をかける対象となるCGAffineTransformを指定するパターンです。 こんな感じ。 view.transform = CGAffineTransformMakeScale(1.2, 1.2);view.transform = CGAffineTransformRotate(view.transform, RADIAN(50));view.transform = CGAffineTransformTranslate(view.transform, -30, 30); 注意する点として、こちらは一見「1.2倍に拡大」⇒「右に50°傾ける」⇒「左に30px、下に30px移動」ってな変換をしてるイメージですが、Makeが付かないCGAffineTransformXXXの関数は第2引数の処理の後、第1引数のCGAffineTransformを掛けるので、 ①「1.2倍に拡大」②「右に50°傾ける」⇒①③「左に30px、下に30px移動」⇒② となり、実際は「左に30px、下に30px移動」⇒「右に50°傾ける」⇒「1.2倍に拡大」という処理になります。 5.2.CGAffineTransformを合成するパターン 複数のCGAffineTransformを合成したものを最後に適用させるパターンです。 CGAffineTransform t1 = CGAffineTransformMakeTranslation(-30, 30);CGAffineTransform t2 […]

View More

UITableViewとかUICollectionViewとかがズレるとき

暖かいです。もうすっかり春です。だから今日は服を着ないで過ごそうと思います。 さて、iPhoneアプリを作ろうとキーボード(あっきぃの数少ない友だち)を叩いているとこんなエラーが。 the behavior of the UICollectionViewFlowLayout is not defined because: the item height must be less than the height of the UICollectionView minus the section insets top and bottom values. 出ました。英語です。 (誰か早く関西弁でエラーを吐き出すプラグインを作ってください。) どんな意味か知りませんが、 「UICollectionViewのアイテムの高さというか座標というかなんかそんな感じのがUICollectionViewの高さより小さいよ。クズめ。」 みたいなニュアンスだと思います。 状況としては、UINavigationBarが非表示のViewControllerから、UINavigationBarが表示されているViewController遷移する感じのところにUICollectionViewがあるって感じ。 あーこれはUINavigationBarの表示&非表示でScrollView系のInsetsが自動で変更してくれるような機能が備わっているのではないだろうか。そしてあっきぃに生きる資格はほぼ無いのではないだろうか。 との予想の下、調べてみるとこんなプロパティがUIViewControllerあるのでした。 @property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets NS_AVAILABLE_IOS(7_0); // Defaults to YES このautomaticallyAdjustsScrollViewInsetsの値がデフォルトでYESなので、 きっといいタイミングでNOにすればいいのです。 とりあえずインスタンス生成時に変更しておけばいいだろうとそのUIViewControllerにこんな記述を追加。 -(instancetype)init{        self = [super init];        if(self) {                self.automaticallyAdjustsScrollViewInsets = NO;        }        return self;} 結果は… 治った。 ScrollView系がズレるのは他にも色々原因があると思うので、参考の1つとしてお考えくださいまし。 ではでは。

View More

Objective-C 指定したディレクトリ以下の全ファイルを表示

こんにちは。 最近なんだかまた生命線が濃くなった気がするあっきぃです。 無駄な動きで生傷ばかり増やしているので、なんか疲れるお仕事ください。よろしくお願いします。 (傷もすぐ治るよ!) さてさて 今日はこんな関数を用意しました。 +(NSArray*)allFilesOfDirectroyAtPath:(NSString*)dirPath{        NSMutableArray *dirs = [NSMutableArray array];        NSMutableArray *files = [NSMutableArray array];        NSFileManager *fileManager = [NSFileManager defaultManager];        NSError *error;        NSArray *list = [fileManager contentsOfDirectoryAtPath:dirPath error:&error;];        for(NSString *name in list) {                NSString *fullPath = [dirPath stringByAppendingPathComponent:name];                BOOL isDir;                if ([fileManager fileExistsAtPath:fullPath isDirectory:&isDir;]) {                        if (isDir) {                                [dirs addObject:fullPath];                        } else {                                [files addObject:fullPath];                        }                }        }        for(NSString *subDirPath in dirs) {                NSArray *subFiles = [self allFilesOfDirectroyAtPath:subDirPath];                [files addObjectsFromArray:subFiles];        }        return files;} 指定したディレクトリ内の全ファイルをフルパスで取得する関数です。 再帰的に呼び出しているのがポイントですね。 使う時はこんな感じ。 NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];NSArray *files = [MYClass allFilesOfDirectroyAtPath:libPath];NSLog(@”%@”, files); 結果はこんな感じ (        “/var/mobile/Containers/Data/Application/123CAD20-DEFE-9922-DADE-A12608D099EE/Library/Caches/JMCache/JMImageCache-2802983090”,        “/var/mobile/Containers/Data/Application/123CAD20-DEFE-9922-DADE-A12608D099EE/Library/Caches/JMCache/JMImageCache-3419541678”,        “/var/mobile/Containers/Data/Application/123CAD20-DEFE-9922-DADE-A12608D099EE/Library/Caches/JMCache/JMImageCache-3911839920”,        “/var/mobile/Containers/Data/Application/123CAD20-DEFE-9922-DADE-A12608D099EE/Library/Caches/JMCache/JMImageCache-4019589813”,        …) あるとたまに便利。

View More

iOS8からUIAlertViewが廃止 代わりに使うのはUIAlertController

iOS8からUIAlertViewのコールバックが上手く動かないなーあとそういえば4日もヨーグルト以外何も食べてないなー外出るのめんどいなーといいつつ、サイフ片手に焼き肉弁当と幕の内弁当とおにぎり3つを買いにコンビニへ行こうとしているそこのあなた。 食べ過ぎです。 そこで今回はiOS8から仲間入りしたUIAlertControllerをどのように使うのか、iOS8とiOS7以下を場合分けで対応したコードを書いてみましょう。(BlocksKit使用) えいやっ NSString* message = @”この画像を削除しますか”; //実際は「message」を「massage」にするとちょっと面白い //iOS8以上if([UIAlertController class]) {        UIAlertController* ac = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleAlert];        [ac addAction:[UIAlertAction actionWithTitle:@”削除” style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) {                //なんか実行        }]];        [ac addAction:[UIAlertAction actionWithTitle:@”キャンセル” style:UIAlertActionStyleDefault handler:nil]];        [self presentViewController:ac animated:YES completion:nil];}//iOS7以下else {        UIAlertView* av = [[UIAlertView alloc] bk_initWithTitle:nil message:message];        [av bk_addButtonWithTitle:@”削除” handler:^{                //なんか実行        }];        [av bk_addButtonWithTitle:@”キャンセル” handler:nil];        [av show];} なんとなく形は似てますね。 UIAlertControllerの方はUIViewControllerなので、現コン(現在のUIViewController)からpresentViewControllerしなければなりませぬので注意。 あと季節の変わり目は体調管理に注意。

View More

iOS7でも画像をLINEで送れるようにする方法

人と話すことがより一層減ってきて最近日本語が上手に出て来ないようになって来ました。先日はカフェに行ったとき「アイス」という言葉が出てこなくて「ホ、ホットじゃない奴ください」と言いました。頭の片隅に浮かんだ「クール」という言葉を発しなくて良かったと思います。 さて、iOS7からなんだかわかりませんが別アプリからLINEへ画像をシェア出来なくなったなんてことが発生しているようです。 LINEの公式サイトでも出来ないよっ的なことが書いてあります。 ところがちょいとコードをいじるだけで出来るようになります。 こんな行を UIPasteboard *pasteboard = [UIPasteboard pasteboardWithName:@”jp.naver.line.pasteboard” create:YES]; こんな行に変えればOKです。 UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; 名前付きのPasteboardがiOS7から使用できなくなったけども、generalPasteboardだったら使えるよっ というお話でした。 参考になれば。 ではでは♪ 追記(2014-04-16 00:07)http://d.hatena.ne.jp/s-0samu/20140323/1395552188より送る画像はpngじゃないとダメだそうです。

View More