NSSplitView

今すぐどうこうというわけではないが、NSSplitView を使えるとアプリのウィンドウの表現が豊かになりそうなので、ちょっと調べる。

ネット上で使えそうなリソースは・・・

How to Use NSSplitView in a macOS app

まあ、良い記事ではあると思うけど、ちょっと応用的でしょうか。

動画もあったが、現代的ではない。

いつもの通り、公式ページもチェック。

 

結局、自分で手を動かしてまあまあ使えるようになった。

上半分は Metal の View で下半分が NSView を Core Graphics で描画したものです。
NSSplitVewDelegate プロトコルを適用するところで、おかしな挙動するんじゃないかと思ってましたが、そんなことはなく。結果オーライということで。

静止画だと伝わらないですが、ディバイダで上下の比率を変えることができます。

今回はちょっと楽して ViewController に NSSplitVewDelegate プロトコルを適用してます。

 

retain, release と -fno-objc-arc

これまで UI パーツの使い方を割と丁寧におさえてきたが、ここら辺で cocoa (最近だと AppKit というのかな?)アプリの作成に慣れるために、個人的に試験的なアプリを作成している。

ARC をオフにするには

その際に「これはいくらなんでも説明不足なんじゃ?」と思ったのが、ARC の使い方。

まず、「現在ではデフォルトで ARC がオンになっている」みたいなことは書かれているが、では、どうやって ARC をオフにしていいのか?そうすることのメリットは?みたいな説明はほとんどなされていない。

いやあ、これだと、スニペットみたいなコードは書けても、アプリを作成する際に色々と不都合が起こると思う。

その説明はいったんおいて、実用的なことを先に書くと、ARC = オンになっている Obj-C プロジェクトである部分だけをオフにしたいならば、TARGETS -> Build Phase -> Compile Sources でオフにしたいファイルの Compiler Flags に -fno-objc-arc というオプションを与える

これで、このファイルに含まれるクラスの ARC は無効になる。
あるオブジェクトを保持したければ retain (メソッド)を、破棄したければ release (メソッド)を明示する。

上の例では AppDelegate にこのオプションを与えたが、多分、これはかなり実用的な例。
ワイが試験的に作成しているアプリはまだ構造はさほど複雑ではないので、WindowsController は AppDelegate に集約している。
この時、困ったのは、あるウィンドウを閉じた時、(ARC をオンにしていると)そのウィンドウを管理しているコントローラーの存在が、不安定なように見えたこと。
ウィンドウをクローズするというのは、ウィンドウオブジェクトが破棄されたのか、それとも見えなくなっているだけでどこかにあるのかなどいくつか可能性があると思うが、この時の挙動がはっきりしない。

例えば、あるウィンドウのコントローラー(のポインタ)を wc としたとき

if(wc = nil){
  //処理
}

のようなコードを書いても、思ったような処理ができなかった。

だが、ARC をそこだけオフにしてみたところ、今の所狙ったようで動作している。

問題は使い分け

ARC に関してある程度把握はできたが、だからと言って、以降、すべて ARC=オフ にしてコーディングするかといえば、そんなことはないと思う。

まだ慣れていないせいもあると思うが、生成したすべてのオブジェクトで参照カウンタを気にするのは大変負担のように思える。

具体的な使い分けに関しては(この記事以外、ほとんど和文の資料はないと思うが)

retain と release の関係について

を参照してください。

 

nullptr -> new -> delete in C++

ネタに困ったら、ポインタ話。

以前にポインタを習得するには、概念だけではなく、malloc -> free のような実用的なコードも重要、みたいな話はした。

じゃあ、C++ では?ってことで、nullptr -> new -> delete の簡単なサンプル。


#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    
    char *test = nullptr;
    
    //test = new char[100];
    
    if(test == nullptr){
        NSLog(@"test is nullptr");
    }else{
        NSLog(@"test is not nullptr");
    }
    
    delete test;
 
    return 0;
}

このままだと test is nullptr が、コメントアウトを外せば test is not nullptr が表示されます。

しかし、C に比べるとぐっと取り扱いが簡単になったね。

 

Objective-C と Java

Objective-C と Java にまつわる戯言。

リアルでは、Web 系にも手を出しているワイだが、このブログでは、どういうわけか上の二つの言語、というか環境に関する記事が多い。

理由は色々とある。

まず、個人的に、現在では主流ではないが「まだまだ使える」といったブツに弱いという癖があるので、それが出たかなあとは思う。

まあ、気合いの入った記事が少ないので、書けば、検索で上位にきやすいという現実的な理由もある。

あとは、この手のマイナーな環境に注目した方がこの業界の実態書きやすいってのもある。

記事を書く上で、情報が乏しいので、リアル・ネットの勉強会などに顔を出した。出不精な方だが、その程度のことはやる。

まー、不愉快な目にはあったさ。

使えない古参のマウンティングはここでもまた

以前にもちらっと書いたのだが、使えない古参からのマウンティングはやはりあった。

なんだけど、「お前の名前、ググったけど、2つくらいしか記事なかったぞ」というのが実態で、この怒りをどこにぶちまけていいものやら。

また、言っている内容がひどい。誰でも言えるようなことばっかり。

(続く)

 

NSTimer

ここしばらく Objective-C & MacOS の話題が続いているが、深い理由はない。

意外に使えることがわかってきて、この環境が好きになってきたから。

今回は、NSTimer の話。

結論から書くと、簡単に試すことができる。

タイマー関係といえば、昔、Java でえらい目にあったことがある。
動作がむちゃくちゃ不安定

まあ、Java の実行環境を考えるとしょうがないでしょう。

サンプル

それはともかく、検証に使ったソースコードは github にあげてあるのでよろしく。


@implementation Timer

-(id)initWithTimer
{
   self = [super init];
  if(self){
     NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0f
                                                       target:self
                                                     selector:@selector(doTask:)
                                                     userInfo:nil
                                                      repeats:YES];
     //[timer fire];
    }

     return self;
}

-(void)doTask:(NSTimer *)timer
{
   //[timer invalidate];
   NSLog(@"timer");
}

@end

コーディング自体は簡単。
上のように Timer クラスを作って、AppDelegate から呼び出すのみ。

これでタイマー処理ができてしまう。

実行すると所定の間隔で doTask メソッドを実行してくれます。