iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
Cocoaのプロセス間通信について調べてみた。今回はパイプだ。
/* ディレクトリ/配下の一覧を取得するプロセスを用意 */
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/ls"];
[task setArguments:[NSArray arrayWithObject:@"/"]];
/* 渡されたデータを読み取るパイプを用意 */
NSPipe *pipe = [[NSPipe alloc] init];
NSFileHandle *readEnd = [pipe fileHandleForReading];
/* 先ほどのプロセスの標準出力にパイプを繋げる */
[task setStandardOutput:pipe];
/* 実行 */
[task launch];
/* パイプに渡されたデータを印字 */
NSData *stdOutData = [readEnd availableData];
NSLog(@"%@", [[NSString alloc] initWithData:stdOutData encoding:NSUTF8StringEncoding]);
これに似たコマンドは、ちょっと違うが以下かな?
$ /bin/ls / | tee
最近はiOSのアプリケーション開発の比率が高くなっているので利用する機会が減ってきているが、OSXでは異なるアプリケーションに対して通知を送る事ができる。
通知を受け取る側(DistributedServer)のコードは以下のとおり。
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSLog(@"%s", __func__);
[self _registerForNotes];
}
- (void)_registerForNotes
{
NSLog(@"%s", __func__);
NSDistributedNotificationCenter *dnc = [NSDistributedNotificationCenter defaultCenter];
[dnc addObserver:self
selector:@selector(_handleDistributedNote:)
name:@"DemoDistributedNote"
object:nil];
}
- (void)_handleDistributedNote:(NSNotification *)note
{
NSLog(@"%s Recieived Distributed Notification!:%@", __func__, note);
}
@end
通知を送る側(DistributedClient)のコードは以下のとおり。
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSLog(@"%s", __func__);
[self _postNotes];
}
- (void)_postNotes
{
NSLog(@"%s", __func__);
NSDistributedNotificationCenter *dnc = [NSDistributedNotificationCenter defaultCenter];
[dnc postNotificationName:@"DemoDistributedNote"
object:nil];
}
@end
DistributedServerを起動した後に、DistributedClientを起動すると、アプリケーション間で通知が送られることが確認できる。
今度は、Distributed Objects。まずは、プロトコルを定義。
@protocol RemoteObjectProtocol
- (oneway void)receiveString:(NSString *)string;
@end
サーバ側を実装。クライアント側からのメソッド呼び出しに対応。
@interface AppDelegate () <RemoteObjectProtocol>
- (void)_registerForDistributedObjects;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[self _registerForDistributedObjects];
}
- (void)_registerForDistributedObjects
{
NSConnection *conn = [NSConnection defaultConnection];
[conn setRootObject:self];
if ([conn registerName:@"DistributedServer"] == NO) {
NSLog(@"%s error", __func__);
}
}
- (oneway void)receiveString:(NSString *)string
{
[self.label setStringValue:string];
}
@end
次は、クライアント側。
@interface AppDelegate ()
- (void)_postForDistributedObjects;
@end
@implementation AppDelegate
- (IBAction)postForDistributedObjects:(id)sender
{
[self _postForDistributedObjects];
}
- (void)_postForDistributedObjects
{
id remoteObject;
remoteObject = [NSConnection rootProxyForConnectionWithRegisteredName:@"DistributedServer"
host:@""];
[remoteObject setProtocolForProxy:@protocol(RemoteObjectProtocol)];
[remoteObject receiveString:[NSString stringWithFormat:@"%@", [[NSDate date] description]]];
}
@end
名前DistributedServerでサーバを探して、プロトコルRemoteObjectProtocolのメソッドを呼ぶと、サーバ側のメソッドが実行される。
未だに需要があるという事で、現在では元の文書を入手する事が難しいということで、MacAppやTCLの命名規則をまとめる。
CName/TName クラスの名前
aName 形式パラメータ
cName 静的データメンバ
fName フラグ。通常はBoolean型データメンバ。
gName グローバル変数
kName 定数。#define, enum, または、constで定義。
itsName データメンバ
thename 変数。通常はローカル変数またはデータメンバ。形式パラメータに使用される事もある。
macName Macintoshデータ構造体。データメンバまたはローカル変数として使用。
IName CNameクラスの初期化関数。
Dispose CNameクラスの終了関数。
少し、用語がおかしい部分があるが、当時のメモのそのまま掲載している。
iOSからLINEでメッセージを送るのは簡単だ。アプリケーションで以下のURLを呼べばいい。
line://msg/text/メッセージ
ただし、メッセージはUTF-8でURLエンコードされている事。
もし、端末にLINEがインストールされていない場合は、以下のURLで呼ぶと、iTunes StoreのLINEのページを開いてくれる。
http://line.me/R/msg/text/?メッセージ
サンプルコードでは、端末にLINEがインストールされているかどうかでURLを切り替えるようにしている。
- (IBAction)sendLINE:(id)sender
{
NSString *text = [self.textView.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *urlFormat = nil;
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"line://"]]) {
urlFormat = @"line://msg/text/%@";
}
else {
urlFormat = @"http://line.me/R/msg/text/?%@";
}
NSString *urlString = [NSString stringWithFormat:urlFormat, text];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
}
漢字混じりの日本文の読み仮名を得るサンプルコードを作ってみた。
- (IBAction)doRuby:(id)sender
{
/* テキストフィールドから日本文を読み取る */
NSString *inputText = self.inputTextField.stringValue;
NSMutableString *outputText = [[NSMutableString alloc] init];
CFRange range = CFRangeMake(0, [inputText length]);
CFLocaleRef locale = CFLocaleCopyCurrent();
/* トークナイザーを作成 */
CFStringTokenizerRef tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault,
(CFStringRef)inputText,
range,
kCFStringTokenizerUnitWordBoundary,
locale);
/* 最初の位置に */
CFStringTokenizerTokenType tokenType = CFStringTokenizerGoToTokenAtIndex(tokenizer, 0);
/* 形態素解析 */
while (tokenType != kCFStringTokenizerTokenNone) {
range = CFStringTokenizerGetCurrentTokenRange(tokenizer);
/* ローマ字を得る */
CFTypeRef latin = CFStringTokenizerCopyCurrentTokenAttribute(tokenizer,
kCFStringTokenizerAttributeLatinTranscription);
NSString *romaji = (__bridge NSString *)latin;
NSString *token = [inputText substringWithRange:NSMakeRange(range.location, range.length)];
/* 平仮名に変換 */
NSMutableString *furigana = [romaji mutableCopy];
CFStringTransform((CFMutableStringRef)furigana, NULL, kCFStringTransformLatinHiragana, false);
[outputText appendString:furigana];
DBGMSG(@"%s token(%@) latin(%@) furigana(%@)" ,__func__, token, latin, furigana);
CFRelease(latin);
tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer);
}
CFRelease(tokenizer);
CFRelease(locale);
/* レベルに読み仮名を設定する */
[self.outputLabel setStringValue:outputText];
}