AndroidからはじめるiOS

AndroiderがiOSアプリ開発に挑戦するメモ

iOS再入門〜開発前の環境メモ〜

諸事情あって久しぶりにiOSを書くことになったら実に3年ぶりだったらしい。 コード書き始めるまでの諸々メモ

XCode

2018年3月27日現在、安定版のXcodeは9.2、macOS High Sierra 10.13.3 最新はXcode9.3 beta 4、macOS High Sierra 10.13.4 beta 6 言語はSwiftならバージョンは4.0.3...?最新では4.1まで出ている。 Swiftについて調べると3以前の書き方の記事が大量に出てくるのが地味につらい・・・

BuildSettingsから対象のSwiftバージョンを変更できるが、バグフィックスバージョンの指定などはできない。

f:id:mochico1105:20180327122857p:plain

iOSの最新バージョンは11.2.6で、iPhone実機にインストールするにはXcodeやらmacOSのアップデートが必要だったりした。

パッケージマネージャ

CocoaPods

  • https://cocoapods.org/
  • 2011年ごろからある。Swiftに対応したのは2014年の12月(Swiftが発表されたのが2014年)
    • Objective-Cからの資産も多い
    • Firebaseも公式提供はCocoaPodsからのみ
  • gem
  • pod installしてできるworkspaceで開発を行う
  • 依存関係の作成及び更新まですべてやってくれる

Carthage

  • https://github.com/Carthage/Carthage
  • これ自身がSwift製で2014年リリース
    • 対応していないライブラリもある
  • 読み方はカーセッジらしい
  • brew install carthage
  • 依存ライブラリをxcodebuildで一度ビルドすればよいので速いっぽい
  • プロジェクトへの統合(BuildPhases > Run Scriptへの追加など)は自分で行わなければならない
  • 中央リポジトリ的なものはない

なおCharthageのほうが速いということで利用することにしたけど必要(Firebase)に迫られてCocoaPodsと両方導入した。 単純なビルドであれば特に困っていない。

Developer Account

Xcodeのダウンロード、ビルドPCに接続した実機へのインストールまではひとまず無料のアカウントで可能ということで一旦。

全体としては iOSアプリを作るときのおすすめ構成 – Swift・iOSコラム – Medium を大変参考にさせていただいております。

iOSのデフォルトのSNS投稿を呼び出してみる

シェアボタンを押すと下から出て来て、
iPhone本体でログインしたSNSアカウントでシェアできるあの機能。
Androidの暗黙的Intentに似ているかもしれな。
iOSのこの機能を「アクティビティ」、実装するためのクラスをUIActivityViewControllerと言うらしい。

ガイドラインはこちら。iOSヒューマンインターフェイスガイドライン: コンテンツビュー

NSArrayに入れたコンテンツを処理出来るアプリおよび機能が列挙されたViewが現れる。

- (IBAction)shareBtnAction:(id)sender {
    UIImage image = [UIImage imageNamed:@"image_name"];
    NSArray activityItems = @[@"title", image];
    UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:activityItems [self presentViewController:activityView animated:YES completion:^{
    }];
}

f:id:mochico1105:20140628230957p:plain

注意点として、端末ですでに認証しているSNSしかここには出てこない。

UILabelの高さ可変とUIScrollViewでハマった件

UILabelはAndroidのTextViewでwrap_contentのように勝手に高さ可変にはなってくれない!

UILabelの高さを合わせる方法は、自分で高さを計算してセットする方法と、sizeToFitを使用する方法がある。
今回はsizeToFitを使用した方法を紹介する。

//
//  MMViewController.m
//  MochiMochiSample
//
//  Created by mochico 2014/06/10.
//  Copyright (c) 2014年 mochico. All rights reserved.
//

#import "MMViewController.h"

@interface MMViewController ()

@property UILabel *flexibleHeightLabel;

@end

@implementation MMViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSString *dummyText = @"どう考えても一行の幅に納まらない長いテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト";
    _flexibleHeightLabel = [[UILabel alloc] initWithFrame:CGRectMake(
                                                                      0
                                                                      , 0
                                                                      , 280
                                                                      , 5000)]; // 適当な高さ
    [_flexibleHeightLabel setLineBreakMode:NSLineBreakByWordWrapping];  // 改行設定
    [_flexibleHeightLabel setNumberOfLines:0];  // 行数指定。0で指定なし
    [_flexibleHeightLabel setText:dummyText];   // sizeToFitより前にテキストをセットする
    [_flexibleHeightLabel sizeToFit];   // テキストの量に応じて高さを変える

    [_scrollView addSubview:_flexibleHeightLabel];   // storyboardからドラッグしてきたscrollView
}

ここで問題はstoryboard、xibから作成したUILabelでは、
AutoLayout指定で下側のconstraintを指定しなければsizeToFitが効かないということ。
ScrollView内のcontentsにconstraintを設定する方法がなさそう、かつ、
UIScrollViewはcontentSizeを正しく設定しないとスクロールしないので、 可変にしたいUILabelはコード上で生成し高さを計算してcontentSizeを設定することになる。
- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    _scrollView.contentSize = CGSizeMake(_scrollView.contentSize.width, CGRectGetMaxY(_flexibleHeightLabel.frame));
}

initWithNibNameでLabelをScrollViewのsubViewに追加しているのでviewDidLayoutSubviewsで高さが決定される。
CGRectGetMaxYで最後のView.frameの高さを取得しcontentSizeに設定する。


【参考URL】
http://9ensan.com/blog/smartphone/iphone/iphone-uilabel-height-calc/
UILabelで高さを動的に変えるには - 3分クッキング
Storyboard上の設定でUILabelを動的に変化させる - makoラボ

SocialFrameworkを使って投稿してみる

iOS6以降ではfacebookTwitterとの連携する際SocialFrameworkを使用することができる。

単純に投稿のみ行う場合は以下のとおり。
#import <Social/Social.h>
#import <Accounts/Accounts.h>

- (void)tweetPost { SLComposeViewController *twitterPostVC = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]; [twitterPostVC setInitialText:@"InitialTweetText"]; [self presentViewController:twitterPostVC animated:YES completion:nil]; }

- (void)facebookPost { SLComposeViewController *facebookPostVC = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook]; [facebookPostVC setInitialText:@"InitialFacebookPostText"]; [self presentViewController:facebookPostVC animated:YES completion:nil]; }

特別な権限などは特にいらない。


参考リンク:
3周遅れぐらいでiOSのSocial.frameworkを使ってみる - Qiita Social FrameworkをつかってFacebookの友達のプロフィール写真を取得しよう。 - みかづきブログ その3

AFNetworkingを使ってJSONと画像を送ってみる

ライブラリ導入までの無駄な紆余曲折は前回の通り。

本題、通信ライブラリ、AFNetworkingを導入する。
AFNetworking/AFNetworking · GitHub

ネットワーク通信回りのライブラリで、Androidで言えばVolleyに近いですね。
リンゴ社が推してるわけではありませんが。

今回やりたかったのはJSONのテキストと画像をPOSTして、結果のJSONを受け取ること。
公式のREADMEのMulti-Part Request が一番近そう。

サンプルのコードでは画像がローカルに保存されているパスだったが、
UIImageとして持っている画像を送りたかったので、先にUIImageからNSDataに変換。
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);

サンプルの
[formData appendPartWithFileURL:filePath name:@"image" error:nil];
部分を
[formData appendPartWithFileData:imageData name:@"image" fileName:@"tmp.png" mimeType:@"image/jpeg"];
上記のように変更する。
[manager POST:@"http://hoge.fuga.com/" parameters:param constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    [formData appendPartWithFileData:imageData name:@"image" fileName:@"tmp.png" mimeType:@"image/jpeg"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"Success: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

iOSでカメラを使用してみる2つの方法①UIImagePickerController

Androidではカメラを使用するとき大きく分けて、Intentで標準カメラを起動する方法と、
Cameraインスタンスを使用する方法がある。
アプリの機能としてのカメラの重要度や、撮影画面にカスタムを加える必要があるかなどでこれらは使い分ける。
Androidほどではないが、iOSでカメラを使用するときにも用途に応じて大きく2つの方法がある。
iOSの公式リファレンスでは カメラ操作のプログラミング で詳しく書いてある。

①UIImagePickerControllerを使用する

この方法はiPhoneの標準カメラUIを呼び出す方法です。
AndroidのIntentで呼び出すカメラのように別のアプリを呼び出すわけではないですが、
アプリ内で動画への切り換えやフラッシュ、サイズ変更など標準的な機能も使用する事ができます。
- (BOOL) startCameraControllerFromViewController: (UIViewController*) controller
{
    if (([UIImagePickerController isSourceTypeAvailable:
          UIImagePickerControllerSourceTypeCamera] == NO)
        || (controller == nil))
        return NO;
    UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
    cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
    [controller presentViewController:cameraUI animated:YES completion:nil];
    return YES;
}
これで最低限標準のカメラが表示されるようになる。
iOSのリファレンスでは
[controller presentViewController:cameraUI animated:YES completion:nil];
の部分が
[controller presentModalViewController: cameraUI animated: YES];
になっているが、このメソッドはiOS6以降ではDupricatedになっている。

表示有無が設定できるボタンについては以下のコードで設定できる。
// ユーザが写真またはムービーのキャプチャを選択するためのコントロールを表示する
// (写真とムービーの両方が利用可能な場合)
cameraUI.mediaTypes =
    [UIImagePickerController availableMediaTypesForSourceType:
    UIImagePickerControllerSourceTypeCamera];
// 写真の移動と拡大縮小、または
 // ムービーのトリミングのためのコントロールを隠す。代わりにコントロールを表示するには、YESを
使用する。
cameraUI.allowsEditing = NO;

アイコンを変更してみる

Xcode Overview: Add Icons, Images, and Effects

iOSヒューマンインターフェイスガイドライン: アプリケーションアイコン

f:id:mochico1105:20140430114529p:plain

プロジェクトのimages.xcassetsのAppIconに対応するサイズの画像をドラッグ&ドロップ
勝手に角丸にされるので表示はこんな感じになります。

f:id:mochico1105:20140430121201p:plain