読者です 読者をやめる 読者になる 読者になる

まいまいワークス

主にiPhoneアプリの開発で考えた事、調べた事、感じた事などを記していきます。

【swift】変数のオプショナル型

swiftの変数は基本的にnilを許容しません。
しかしながら、textFieldやAPI経由で外部から値を取得する場合など、構造上、値がnilになりうる場合があります。

そこで利用されるのがオプショナル型の変数です。
変数をラップする(オプショナル型を使う)をnilを扱うことができ、実際にその変数を使用するためにはアンラップする必要があります。

絶対に値がnilにならない場合

変数宣言時に!を付ける黙示的アンラップ型を使用
自動的にアンラップしてくれるためnilが入ると即落ちる

var aaa:Int! = 10

通常の場合

変数の宣言時に?をつける

var str1:String?
str1 = "zzzz"

アンラップの方法

str1がnilの場合??のあとの項目がresultStrに代入される

var str1:String?
str1 = "zzzz"
let resultStr = (str1 ?? "nilですよ!")
print("result=",resultStr)

str1がnilでなければstr1がstrに代入される。 nilの場合は代入は行われずelse以下が実行される。

if let str = str1 {
    print(str)
}else{
    print("nil!!!!!")
}

【swift】インスタンス変数、クラス変数、ローカル変数

//すべてのクラスから参照可能
let global_let = "global"  //グローバル変数

class myClass: NSObject {

    public let aaa = "abc"     //インスタンス変数(クラス内の共通変数)、インスタンス化すると他クラスから参照可能
    let bbb = "def"                //インスタンス変数(クラス内の共通変数)、インスタンス化すると他クラスから参照可能
    private let ccc = "ghi"        //インスタンス変数(クラス内の共通変数)、他クラスから参照不可
    static let ddd = "jkl"     //クラス変数、他クラスからmyClass.dddで参照可能
    
    func method1(){
        
        let xyz = "xyz"        //ローカル変数
        print("xyz=",xyz)    //メソッド内でのみ有効
    }

}
//上記変数を他のクラスから参考

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        print("global=",global_let)


        let myclass = myClass()       //インスタンス化
        
        print("aaa=",myclass.aaa)
        print("bbb=",myclass.bbb)
//     print("ccc=",myclass.ccc)     //プライベート変数なのでエラーになる
        print("ddd=",myClass.ddd)
        
        
        myclass.method1()       //myClassのmethod1を実行
        
    }

}

//実行結果
global= global
aaa= abc
bbb= def
ddd= jkl
xyz= xyz

【swift】変数を利用する


/** 定数の定義 */
//letで宣言した値は後から変えられない
let aaa = "abc"            //型を宣言しなくても型推論でStringと認識
let bbb:String = "xyz"    //String型を明示

/** 変数の宣言 */
var ccc = 123        //型を宣言しなくても型推論でIntと認識
var ddd:Int = 789   //Int型を明示

ccc = 1234          //変数なので値を変えられる
ddd = 7890          //変数なので値を変えられる

var eee:Int         //変数なので型だけ宣言して値は後から代入できる
eee = 456           //変数なので値を変えられる

var fff              //型の宣言もなく、値の代入もないとエラーになる
fff = 777           //値も型も指定されないとコンパイラも困っちゃう!

print("aaa=",aaa)
print("bbb=",bbb)
print("ccc=",ccc)
print("ddd=",ddd)
print("eee=",eee)


//実行結果
aaa= abc
bbb= xyz
ccc= 1234
ddd= 7890
eee= 456

端末のpush通知設定情報をアプリ側で取得する

メモ

    UIUserNotificationSettings* userConfig = [[UIApplication sharedApplication] currentUserNotificationSettings];
    NSLog(@"cfg=%lu",(unsigned long)userConfig.types);
    
    /** 
     7:通知、バッジ、サウンドOK
     6:通知、サウンドOK、バッジNG
     5:通知、バッジOK、サウンドNG
     4:通知OK、バッジ、サウンドNG
     0:通知NG、なのでバッジ/サウンドもNG
     */

SDWebImageでアニメーションgifとWebPを表示させる

SDWebImageはなかなか優秀な子で、JPEGPNG以外にもGIF、WebP形式の画像も表示できるんですね!
アニメーションGIFを使えば表現の範囲が広がるし、WebPを使うと画像の容量が小さくなるので、サーバーや通信帯域などのインフラ資源を有効に使うことができますね。

GIFの表示

これは簡単!
通常、JPEGPNGファイルを表示しているやり方でURLをGIFファイルのURLに書き換えるだけ。

UIImageView* imageview = [[UIImageView alloc] initWithFrame:CGRectMake(10, 330, 200, 150)];
[imageview sd_setImageWithURL:[NSURL URLWithString:@"https://dl.dropboxusercontent.com/u/36343998/bicycle-gif.gif"] placeholderImage:[UIImage imageNamed:@"noImage.png"] options:SDWebImageCacheMemoryOnly];
[self.view addSubview:imageview];

WebPの表示

これもソース部分はGIFと同じです。

UIImageView* imageview = [[UIImageView alloc] initWithFrame:CGRectMake(10, 30, 275, 184)];
[imageview sd_setImageWithURL:[NSURL URLWithString:@"http://www.gstatic.com/webp/gallery/1.webp"] placeholderImage:[UIImage imageNamed:@"noImage.png"] options:SDWebImageCacheMemoryOnly];
[self.view addSubview:imageview];

但し、WebPの場合は下準備が必用です。

cocoaPodの仕込み

cocoaPodsでWebPはSub specsとなっているのでpodfileは以下のようにWebPを指定します。

pod 'SDWebImage', '~> 3.7.1'
pod 'SDWebImage/WebP', '~> 3.7.1'

Xcodeの仕込み

このままではまだWebPが表示されません。
TARGET>Pods-SDWebImageのPreprocessingの設定でPreprocessor MacrosにSD_WEBP=1と追記します。

f:id:cccookie:20150107153330p:plain

これで、WebPファイルを表示できるようになりました! めでたしめでたし。

iOS/objective-Cのマクロ設定のまとめ

必要に応じてdefine.hにマクロを追記していき、次のプロジェクトではそのままマクロファイルを受け継ぐようにしていると、だんだんマクロ設定が増えてきたので一旦まとめてみようかと思います。

画面サイズ

//スクリーンの高さ
#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
//スクリーンの幅
#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
/** 使用例
label.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
*/

バージョン系

//アプリのバージョン
#define APP_VERSION [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"]

//ビルドバージョン
#define BUILD_VERSION [[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"]

//OSのバージョン
#define SYSTEM_VERSION ([[UIDevice currentDevice] systemVersion])

//OSバージョンによる処理の振り分け
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
/** 使用例
if (SYSTEM_VERSION_LESS_THAN(@"8.0")) {
    NSLog(@"8.0未満");
}else{
    NSLog(@"8.0以上");
}
*/

カラー系

#define RGBA(r, g, b, a) [UIColor colorWithRed: (r)/255.0 green: (g)/255.0 blue: (b)/255.0 alpha: (a)]
#define RGB(r, g, b) [UIColor colorWithRed: (r)/255.0 green: (g)/255.0 blue: (b)/255.0 alpha:1.0]   //alpha=1固定の場合
/** 使用例
label.textColor = RGBA(240.0, 129.0, 163.0, 1.0);
このようにRGBとalpha値を数値で指定
*/

#define RGBA_HEX(rgbHex,a) [UIColor colorWithRed:((float)((rgbHex & 0xFF0000) >> 16))/255.0 green:((float)((rgbHex & 0xFF00) >> 8))/255.0 blue:((float)(rgbHex & 0xFF))/255.0 alpha:a]
#define RGB_HEX(rgbHex) [UIColor colorWithRed:((float)((rgbHex & 0xFF0000) >> 16))/255.0 green:((float)((rgbHex & 0xFF00) >> 8))/255.0 blue:((float)(rgbHex & 0xFF))/255.0 alpha:1.0]   //alpha=1固定の場合
/** 使用例
label.textColor = RGBA_HEX(0x00bfff,1.0);
色は頭に0xをつけて16進の値を設定、alpha値は数値で0.0〜1.0を指定
デザイナーは16進数で指定してくることが多いですね。
*/

#define MyAppColorPink RGBA_HEX(0xff69b4,1.0);
/** 使用例
label.textColor = MyAppColorPink;
アプリ毎に色を定義して名前をつけるます。
このかたちで定義しておくと入力時に補完もされるのでかなり楽になります。
*/

言語取得

#define LANGUAGE    ([NSLocale preferredLanguages][0])

retina判定

#define IS_RETINA ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [UIScreen mainScreen].scale > 1)

AppDelegate

#define AD ((AppDelegate*)[[UIApplication sharedApplication] delegate])
/** 使用例
AppDelegate.hでプロパティ宣言
@property(nonatomic, strong)NSDictionary* infoDict;

任意のソースファイルで
#import AppDelegate.h
としておけば
AD.infodictでアプリ内のどこからでも参照可能
*/

通知系

//通知を受ける
#define receiveNotification(receiveName,receiveSelector) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveSelector) name:receiveName object:nil];

//通知を送る
#define sendNotification(sendName,sendObject) [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:sendName object:sendObject]];

//通知の監視を解除
#define removeNotification(removeNotificationName) [[NSNotificationCenter defaultCenter] removeObserver:self name:removeNotificationName object:nil];

/** 使用例
//受け側
//通知の設定
receiveNotification(@"notifiTest",test);
通知の名前と叩くメソッド名を設定

//通知の解除
removeNotification(@"notifiTest");
viewを閉じるタイミングなどで実行
通知の名前を設定

//通知受信時の処理
-(void)test:(NSDictionary*)object{
    NSDictionary* dict = object.object;
    //任意の処理
}

//付加するオブジェクトがnilの場合は
-(void)test{
    //任意の処理〜
}

//通知側
sendNotification(@"notifiTest",infoDict);
通知の名前に続いて付加するオブジェクト(nilでも可)を設定

通知の名前を'#define'で設定するとさらに使い勝手が良くなりますね
#define NTFnotifiTest @"notifiTest"
 */

ffmpegのメモ(自分用)

フォーマット変更、サイズ変更、切り取り(時間軸)、切り抜き(xy)など

ffmpeg -ss 0 -t 6 -i 1420114405.mov -s 320*568 out.mp4
ffmpeg -ss 0 -t 6 -i 1420114405.mov -vf crop=200:300:25:25 out.mp4

-ss:スタート時間
-t:動画の時間
-i:入力ファイル
-s:出力サイズ(拡大縮小)
-vf crop=縦サイズ:横サイズ:原点x:原点y
最後に出力ファイル

アニメーションgifを作るとき

ffmpeg -ss 0 -t 6 -i 1420114405.mov -vf crop=200:300:25:25 -r 15 pngs/%04d.png

#imagemagickを使用
convert -delay 6.67 -layers optimize pngs/*.png image.gif

pngsディレクトリを用意

-r:1秒間のコマ数
-delay 6.67:1フレームの時間(/100秒)
→6.67/100(秒)
1秒間に15コマの場合