継続モナドその2
APIをFutureで返す。bindはとりあえず省略。
@interface Future<V> : NSObject - (void)get:(void(^)(V))cb; @end @interface API<I,O> : NSObject - (Future<O> *)getAPI:(I)input; @end typedef void(^CallBack)(id); typedef void(^CPS)(CallBack); @interface Future() @property (nonatomic) CPS cps; @end @implementation Future - (instancetype)init:(CPS)cps { self = [super init]; if (self) { self.cps = cps; } return self; } - (void)get:(void (^)(id))cb { self.cps(cb); self.cps = nil; } @end @implementation API - (Future *)getAPI:(id)input { CPS cps = ^(CallBack cb) { return cb(input); }; Future *future = [[Future alloc] init:cps]; return future; } @end
継続モナド
Objective-Cで継続モナドを書いてみた。ジェネリクスの機能が貧弱なので辛いところが多い。
Objective-C++でクラス
JSONを使った受け渡しを想定して書いてみた。非効率かも。
#import <Foundation/Foundation.h> @class Engine; typedef NSDictionary JSON; @protocol EngineProtocol <NSObject> - (void)engine:(nonnull Engine *)engine message:(nonnull JSON *)message; @end @interface Engine : NSObject + (nonnull instancetype)engine:(nonnull id <EngineProtocol>)delegate; - (void)tellMessage:(nonnull JSON *)message; @end #include <stdio.h> #include <iostream> class EngineCpp; class EngineCpp { public: EngineCpp(); ~EngineCpp(); void hello(); typedef std::shared_ptr<EngineCpp> Ptr; std::string message; std::string proc(std::string src); }; EngineCpp::EngineCpp() { std::cout << "EngineCpp new" << std::endl; } EngineCpp::~EngineCpp() { std::cout << "EngineCpp delete" << std::endl; } void EngineCpp::hello() { std::cout << "EngineCpp hello" << std::endl; } std::string EngineCpp::proc(std::string src) { return "{\"Hello\":" + src + "}"; } @interface NSJSONSerialization(String) + (NSString *)jsonString:(NSDictionary *)dic; + (NSDictionary *)jsonString_r:(std::string &)str; @end @implementation NSJSONSerialization(String) + (NSString *)jsonString:(NSDictionary *)dic { NSData *d = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil]; NSString *sd = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding]; return sd; } + (NSDictionary *)jsonString_r:(std::string &)str { NSData *data = [NSData dataWithBytes:str.c_str() length:str.length()]; NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; return dic; } @end @interface Engine() @property (nonatomic) id <EngineProtocol> delegate; @property (nonatomic, assign) EngineCpp::Ptr engineCpp; @end @implementation Engine { } - (void)dealloc { NSLog(@"Engine dealloc"); } + (instancetype)engine:(id<EngineProtocol>)delegate { Engine *engine = [Engine new]; engine.delegate = delegate; engine.engineCpp = std::make_shared<EngineCpp>(); return engine; } - (void)tellMessage:(JSON *)message { std::string str = [NSJSONSerialization jsonString:message].UTF8String; std::string result = self.engineCpp->proc(str); NSDictionary *dic = [NSJSONSerialization jsonString_r:result]; [self.delegate engine:self message:dic]; } @end
一文字づつ区切る
NSStringEnumerationByComposedCharacterSequencesを用いる。
NSString *string= @"ハローワールド🗾"; NSMutableArray *list = [NSMutableArray array]; [string enumerateSubstringsInRange:NSMakeRange(0,string.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) { [list addObject:substring]; }]; for (NSString *sub in list) { NSLog(@"%@", sub); for (int i=0;i<sub.length;i++) { NSLog(@"%04x", [sub characterAtIndex:i]); } }
NSCalender
NSDateを用いた演算などができる。
NSCalendar - Foundation | Apple Developer Documentation
iOS8からの日付(NSDate)操作・比較 - Qiita
NSDateFormatter
NSDateComponent
も
参考になる
dev.classmethod.jp
http://www.toyship.org/archives/1665
マクロ関数での注意
defineのマクロ関数でクラス・メソッドに置き換える際、引数の文字と、メソッド名の一部がかぶるとエラーを引き起こす。→ マクロの引数名をかえる。
C++を混載
mmファイルを使うとCの関数(特にObjective-Cのアマルガム的な)が呼べなくなるので注意
NSNotFound
NSNotFoundは型に注意しないでロジックミスになる。注意。
duplicate symbols
久々にはまったが、よくみたところヘッダーでimportしていたファイルが.mになっていた。。
商品の値段とNSNumberFormatter
SKProductの価格の加工などで使う。
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; formatter.formatterBehavior = NSNumberFormatterBehavior10_4; formatter.numberStyle = NSNumberFormatterCurrencyStyle; formatter.locale = locale; NSString *string = [formatter stringFromNumber:price];
クラスで作ってみるIF
Objective-C Advent Calendar 2014に登録していたのですが何もネタが思いつかなかったので、クラスで最小の部品を作ってみようかと思い作ってみました。
クラスIFです。
KatagiriSo/IF · GitHub
使い方は
//ex1 int a = -3; [[IF Condition:((a>=0) ? OK.new : nil) Action:[Do b:^{NSLog(@"a=>0");return OK.new;}] Else:[IF Condition:((a<0) ? OK.new : nil) Action:[Do b:^{NSLog(@"a<0");return OK.new;}] Else:NG.new] ] do];
‥汚いですね。
IFクラスの引数はDoプロトコルを持ちます。
@protocol Do <NSObject> - (id<Do>)do; @end
クラス定義です。
typedef id<Do>(^DoBlock)(void); @interface IF : NSObject <Do> + (IF*)Condition:(id<Do>)condition Action:(id<Do>)d Else:(id<Do>)e; - (DoBlock)getDoBlock; @property (nonatomic) id<Do>Action; @property (nonatomic) id<Do>Condition; @property (nonatomic) id<Do>Else; @end
ConditionにはOKならOKクラスを入れます。
その場合にActionが実行されます。
単なるクラスなので変数に入れられます。あとBlocksにも変換できたり、返り値としてDoプロトコル
が得られたりします。
IF *iff = [IF Condition:((a>=0) ? OK.new : nil) Action:[Do b:^{NSLog(@"a=>0");return OK.new;}] Else:[IF Condition:((a<0) ? OK.new : nil) Action:[Do b:^{NSLog(@"a<0");return OK.new;}] Else:NG.new] ]; DoBlock doblock = iff.getDoBlock; doblock();
何かに使えないか。。
注 Doクラス、OKクラス
@interface Do : NSObject<Do> @property (nonatomic, copy) DoBlock doblock; + b:(DoBlock)doBlock; @end
@interface OK : NSObject<Do> @end @implementation OK - (id <Do>)do { return OK.new; } @end
ヘッダーを眺める
Availability.h
AvailabilityMacros.h
limits.h
stdint.h
stdarg.h
objc/NSObjCRuntime.h
TargetConditionals.h
Foundation/NSMetadata.h
調査中の事々
NSSecureCoding
NSSecureCoding Protocol Reference
以下を読んだ。
Cocoaの日々: NSSecureCoding - セキュアなプロセス間通信への小さな布石
iOS6から。なぜiOS6からかというとXPCサービスの導入で非公開APIとして導入されたらしい。
Cocoaの日々: [Mac] Lion から導入された XPC Services
iOS8での外部extentionとのつながりについて調査中