Xcode で GUI アプリ 4

このシリーズも今回4回目。

継続していて気が付いたことは、アプリの製作は文法の学習とはまた異なった知識が必要だということ。

前回扱った内容はまさにそれで、メニューイベントを管理するクラスをどこに置くか?という話題で、ある程度凝ったアプリならば、NSWindowController の派生クラスに置くのがいいのでは、みたいな話をした。

答えが複数あり、状況によって最適解を探す、というのは、プログラミングに限らず、習得するのが難しい領域の一つなんでしょうね。

前置きはともかく、今回は、特定のクラスが必要になったとき、それを Objective-C でどう構成するかという話。

イニシャライザでインスタンスを返す

どう構成するかはひとまず置いて、定型的な書き方の復習。


@interface Hoge : NSObject
-(nullable instancetype) initHoge;
@end

@implementation Hoge
-(nullable instancetype) initHoge;
{
    self = [super init];
    if(self)
      {
         //初期化処理
       }
   return self;
}
@end

この書き方、昔は無茶苦茶違和感あったけど、最近慣れたな。

なお、initXxx は init family とかイニシャライザなどと言われ、クラスの初期化を受け持つメソッド。
init 以下に適当な文字(列)をつけるが、最初の文字は大文字にする必要がある。

だから、initialize は init familiy ではない

以前に他人のコードを読んでいたとき、同一クラス内で init と initialize が同居していて「は?」と思ったのだが、そういうことらしい。

(続く)

 

Objective-C から Swift へ

Obj-C と Swift を行ったり来たりする時、気にしておいた方がいいポイント。

・・の前に

Obj-C → Swift コンバータ

世間的には Swift ユーザーの方が多い。しかし、既存プロジェクトは Obj-C で書かれている。
という現状なので、(あるんじゃないかと予想はしていたのだが)やはり Obj-C → Swift 自動変換ツールはあるようです。

こちらの記事などどうぞ。

メソッドのラベル

Swift の良い点の一つが、メソッドのラベルがわかりやすいところ。

Obj-C で

[img drawInRect:rect blendNode:mode alpha:alpha]

と書いていたところが、Swift では

img.draw(in:rect blendNode:mode alpha:alpha)

となる。

Obj-C ではメソッドに第一引数が含まれているから、若干わかりにくい。

Swift は型にうるさくない?

ところで Swift 使っていない人ほど見出しのように誤解している。
スクリプト系の言語っぽい雰囲気出してるからかなあ?
単純に使ってないだけ?

実際には、Swift の方が C より変数の型にうるさいです。

コマンドライン実行環境

このブログでは、けっこう言っているし、実演もしていると思うのだが、ワイは(Swift に限らず)簡単なプログラムをコマンドラインで実行することがよくある。

なので、実行環境の整備の仕方。

Swift の場合は Mac のターミナルや VS code のターミナルから swift -v と打ち込むと

swift -v
Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
Target: arm64-apple-macosx13.0
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-help intro

Welcome to Swift!

Subcommands:

  swift build      Build Swift packages
  swift package    Create and work on packages
  swift run        Run a program from a package
  swift test       Run package tests
  swift repl       Experiment with Swift code interactively

  Use `swift --help` for descriptions of available options and flags.

  Use `swift help ` for more information about a subcommand.

と表示される。
(表示されない場合は、コマンドラインツールがインストールされていない、などの不備がある。準備する)

上では swift build コマンドが表示されているが、もっと簡単には swiftc コマンドを使う。

hello.swift
print("hello Swift")

というプログラムがあったとき、swiftc hello.swift を実行すると hello という実行ファイルを作ってくれる。

VS code だとこんな感じになる。

実行できてますね。

Foundation フレームワークと C 標準ライブラリの機能は、特に指示しなくても使えるようです。

なお、ファイルの冒頭に #!/usr/bin/swift を付加してファイル自体に実行権限を与えるとシェルスクリプトっぽく使える。
実際にこの使い方をするかどうかは微妙ですが。

$0 とかいう書き方が気持ち悪い

この記事参照。

zip とか map とか

zip や map も Obj-C では全く出てこない。

この記事参照。

 

Metal 関係リソース物色中

あまり勉強したことがない Metal 関係のリソースを物色中。

公式サンプル

おお!と思ったのは公式のサンプル紹介記事にあったこのプロジェクト(群)。

C++ と書いてあるが、「どーせ、これ Objective-C++ でしょ?」と思っていたが、れっきとした C++ だった。
例えば、Xcode で GUI アプリを作成した際、自動で生成される main.m に相当する部分は

int main( int argc, char* argv[] )
{
    NS::AutoreleasePool* pAutoreleasePool = NS::AutoreleasePool::alloc()->init();

    MyAppDelegate del;

    NS::Application* pSharedApplication = NS::Application::sharedApplication();
    pSharedApplication->setDelegate( &del );
    pSharedApplication->run();

    pAutoreleasePool->release();

    return 0;
}

となっている。
言われてみれば Objective-C++  と C++ との対応はこうですね、って感じ。

三角形ばかり書いていてもつまらん

そんな方はこちらなんかも。

ただし、これは Swift の iOS プロジェクトなので、MacOS に移植する際にはいくらか(↓)修正が必要。

cocoa アプリでの Metal Viewer の取り扱い

手動で追加する。

NSObect のサブクラスとして適当な名前のクラスを作成した後に、MTKViewDelegate を書き加える。

また、以下の二つのメソッドは MTKViewDelegate を継承するには必須のようなので、付け加える。

 

参考(追記)

MacでObjective-cを使ってMetalを初期化

のシリーズを使って勉強しよう・・・と思っていたのだが、これは Objective-C で Metal を扱う際にはイマイチのやり方のようだ。

もともとアップル公式のサンプルは Objective-C で書かれており、これを Swift に移植したものが、上記シリーズ(というかネットに落ちている情報全般)っぽい。

この記事にならって丹念にアップル公式のサンプル眺めていくしかないかな。

 

 

AppDelegate さて Xib では?

MacOS のデスクトップアプリを Xcode で作成する際、UI として storyboard を選べば、自動で appdelegate は生成されるので、簡単なアプリならば、ここで初期化処理すればいい。

が、レガシーなプロジェクトでは xib が使われている場合も多い。

ちょっと調べますかね。

Xcode を起動し、UI を xib でプロジェクトを作成。

MainMenu.xib が自動で生成されるが、この Objects を管理しているのが AppDelegate という構成になっているようだ。

AppDelegate も自動生成されるが、このクラスは以下のように NSApplicationDelegate を継承している。

なるほど。

ただ、レガシーなプロジェクトではこの継承が明示されていないこともあるようだ。
AppController のような名前になっていて初見でなんのことかわからなかった。
もちろん、
– (void)applicationDidFinishLaunching:
– (void)applicationWillTerminate:
は、実装されていたが。
さらに言っておくと WindowController から AppController のイニシャライズをする、というなんとも風変わりな構成になっていた。

こういうのもあるんですね。