頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


macOSでテーブル処理をViewController以外に記述したい

iOSアプリ開発の調子でmacOSアプリに取り組んで泣きを見てる。UIをNSに変えればいいんだろうと思ってた過去の自分に説教したい。

今回はテーブルを表示しようとしたんだが、基本的なことはまあ何とかなった。

macOS NSTableView Tutorial

↑またこちらのサイトにお世話になった。ありがたいことです。

ただstoryboard上にNSTableViewを乗っけた場合、そこからのdelegateやdataSource、クリックを拾うactionはViewControllerにしか繋げられなくて困った。
関連の処理はViewControllerクラスじゃなくて別なHogeManagerクラスに記述したいんだあ、、、なんて時ってあるよね?惰性でやるとViewControllerはどんどん巨大化していくのよ。

ファイル構成図

↑ちなみにHogeMangerはViewControllerクラス内から参照できる。
こういう場合、どうすればいいんだろう???
{
    //ViewConteroller.h

    IBOutlet NSTableView *myTableView;
}

{
    //ViewConteroller.m

    hogeManager = [HogeManager new];
    myTableView.delegate = (id<NSTableViewDelegate>)hogeManager;
    myTableView.dataSource = hogeManager;
}
↑storyboardの扱いが未熟な俺は仕方なくNSTableViewオブジェクトの参照をViewControllerクラスに接続。
コードでdelegateとdataSourceをセットした。ああ、原始的。なんかstoryboard使うやり方ありそうな気がするんだけどなあ?

なおdelegateの設定のところで
Assigning to 'id<NSTableViewDelegate> _Nullable' from incompatible type ‘HogeManager *__strong'
というワーニングが出てたので上のようにキャストしたら消えた。

テーブルを使う時はたいていセルを選択した時の処理を記述したいよね。
storyboardからViewControllerにactionをつないでもいいけどそうするとViewController内で受けたIBActionをHogeManagerに「あいよ!」って渡す処理が必要になる。そりゃ短いけどなんか嫌じゃない?
結局セルのクリックはdelegateでも検出できるらしいのでそっちで拾うことにした。
ただiOSの
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
と言ったわかりやすいのはないようで、、、

NSTableViewで行選択をしたときに呼ばれるデリゲートメソッド: 永遠ログ

↑こちらを参考にさせて頂きました。感謝!


iOSで出力したファイルをAirDropでMacに送信する

iOSアプリで作成、保存したファイルをMac側で使うのにずっとiTunes経由で取得してた。Application supports iTunes file sharingをYESにしとく方法ね。でもこれやっぱり面倒。そこでAirDrop使えばいいんじゃね?と思ってやってみた。

UIActivityViewController Tutorial: Sharing Data

↑Info.plistの設定はこのあたりを参考に。ただ面倒なのでアイコンとかは使ってない(俺のはリリース目的じゃないし)。
public.mime-typeもセットしてない。
拡張子はなんでもいい。.hogeでも.fooでも。

送信するためのiOS側のUIActivityViewControllerあたりのコードがこんな感じ。

{
    //(1)
    NSURL *url = [NSURL fileURLWithPath:fileName];

    //(2)
    NSError *error = nil;
    NSData *data = [saveString dataUsingEncoding:NSUTF8StringEncoding];
    BOOL succeed = [data writeToURL:url options:NSDataWritingAtomic error:&error];

    //(3)
    if (succeed) {
        UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[url] applicationActivities:@[]];
         [self presentViewController:activityViewController animated:YES completion:nil];
    }
}
(1)ここでfileNameはNSStringオブジェクト、ファイルの保存先で拡張子まで含む。
(2)saveStringもNSStringオブジェクトで中身はたんにxmlファイル。これをNSDataオブジェクトに変えて保存する。
(3)ここで指定するactivityItemsはNSURLオブジェクト。当初urlではなくdataもしくはurl,dataを記述しててうまくいかなかった。Info.plistのUTIの設定でConforms to UTIsにpublic.dataってしてるからNSDataオブジェクトを送信する必要があるのかと思ってた。

ともかく、これでめでたく送信することができた。MacのFinderでダウンロードフォルダーに入ってる。長かったなあ、、、


おまけ

UIActivityViewController表示

↑UIActivityViewController でCancelなり処理後にDoneしたらどうこうしたい時の記述はこんな感じで。
{
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[url] applicationActivities:@[]];
        [activityViewController setCompletionWithItemsHandler:
         ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
        // 処理
    }];
}



*versions
macOS Sierra 10.12.6
iOS 11.1.1
Xcode 9.1



macOSでSCNView→png画像を作成、保存する

SCNViewの表示内容からpng画像を作って保存したかったんだ。なおNSSavePanelは使わない。
散々回り道したけど、こんな感じ。

{
    //(1)
    NSImage *image = [sceneView snapshot];
	
    //(2)
    NSData *imageData = [image TIFFRepresentation];
    NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
    NSDictionary *imageProps = [NSDictionary dictionary];
    imageData = [imageRep representationUsingType:NSPNGFileType properties:imageProps];

    //(3)
    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *url =[fm homeDirectoryForCurrentUser];
    NSString *path = [url path];
    NSString *pathStr = [path stringByAppendingPathComponent: @"images/screenshot.png"];

    //(4)
    NSError *error = nil;
    if (![imageData writeToFile:pathToDesktop options:NSAtomicWrite error:&error]) {
        NSLog(@"%@",error);
    }
}
(1)まずNSImageオブジェクトを作る。snapshotで一撃。
(2)NSImageオブジェクトからNSDataオブジェクトを作る。調べるといろんなやり方があるみたい。propertiesに渡すのもなくてもいけそう(でもnilだと警告が出る)。
(3)保存先、ファイル名を指定。imagesってフォルダーを作ってそこに入れてる。
(4)保存。ダメならエラー表示。

sandbox設定
↑XcodeのTarget設定のところのApp SandboxをONにしてる場合、保存先が限られてデスクトップなどには保存できない。
{
    NSString *pathToDesktop = [NSString stringWithFormat:@"/Users/%@/Desktop/screenshot.png", NSUserName()];
}
↑保存先にデスクトップを指定すると

Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “screenshot.png” in the folder “Desktop”.

なんてエラーになる。ただしサンドボックスをOFFにしておけばデスクトップにも保存できた。なおNSSavePanelを使えばサンドボックスON/OFF関係なくどこでも保存できるみたい。

macOSのサンドボックスについてもっと勉強せねば。


サイズの合わない窓用エアコンを取り付けた

ウチの小さい部屋には外に室外機を置くスペースはもちろんそれ用の配管を通す穴もない。つまり元々エアコンを設置できるようには設計されていないんだけど、どうしても設置したくてコロナの窓用エアコンを検討してた。ヒーターを別途置くスペースもないしヒートポンプの方が電気代も安いよなってことで冷暖兼用が欲しい。

ウインドエアコンの取り付け方|ウインドエアコンシリーズ|空調・家電機器|製品情報|コロナ

↑設置に必要な幅として495mm以上とある(冷房専用なら470)。しかし、ウチの窓のサイズを確認すると445mmくらいしかない!
あかんやん、、、と最初はあきらめていたのだけどよくよく調べると実機(CWH-A1817)の横幅は360mmになってる。設置用の枠のサイズはどこを見ても書いてないんだが、実機よりちょっと大きいくらいに見える。まさか窓ストッパーを倒さないと電源が入らない、とかなってないよな?だったら取付枠さえ窓にセットできればなんとかなるんじゃないの?ということでえいや!と注文してみた。だめなら最悪DIYでエアコン設置台兼本棚みたいなのを作るつもりでいた。



窓用エアコン

↑届いたエアコンと設置するところの窓。
取付枠の横幅を測ってみると390mm程度だ。いけるかも?!

取付枠設置後

↑かろうじて取付枠が設置できた!窓ストッパーは最初からあきらめてる。
なお、元々窓のレール(?)部分に衝突防止用部品みたいなのがあってそれがためにうまく取付枠を設置できなかったので、それを強引に取り外してようやく取付枠の設置ができた。

ドレン

↑あせったのがドレン用の部品とかがあったことだ。え?不要だったんじゃないの?と思いサイトを再確認したらそれは冷房専用機であって冷暖兼用機にはドレン工事が必要とあるのだ。あちゃー、やってしもうた、、、と焦ったんだが別に画像の状態でもいいんじゃね?ってことで配管などは設置せず。

設置完了

↑無事に設置完了。試運転したらちゃんと動いたよ。でもこれ使用時には当然窓を開けておく必要があるわけだが、うっかり忘れてしまいそうな気がする。そういう気がするって場合はたいていやってしまうもんだ。取説によると室外側の吸い込み温度が高温になると停止するみたいだけど。

作業時間は2時間ちょいかな。設置に必要な条件を満たしていない方法なので自己責任で。
これでこの部屋でも快適にすごせる。ありがとう、コロナさん!
謎なのは吹出口のルーバーをどう向けようがエアフィルターが引っかかって取り出せないんだけど?


  TopPage  



Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.

FC2Ad