ラベル Objective-C の投稿を表示しています。 すべての投稿を表示
ラベル Objective-C の投稿を表示しています。 すべての投稿を表示

2017-02-23

Objective-C で文字列を join する

Objective-C で文字列配列の join をやるのは面倒と思っていた。Ruby の join みたいなことが出来ると楽なのにー、と。例えばこんなコード:

%w(This is an apple).join(' ') #=> "This is an apple"

で、Apple のマニュアルを見たらあったcomponentsJoinedByString というメソッド。

これを使えば、NSMutableString を使ったり

NSArray<NSString *> *strings = @[@"This", @"is", @"a", @"pen."];
NSString *separator = @" ";

NSMutableString *mResult1 = [NSMutableString new];
for (int i=0; i<strings.count; ++i) {
    [mResult1 appendString:strings[i]];
    if (i < strings.count - 1) {
        [mResult1 appendString:separator];
    }
}
NSString *result1 = [mResult1 copy];
NSLog(@"Text: %@", result1);

Text: This is a pen.

stringByAppendingString: を使ったり

NSArray<NSString *> *strings = @[@"This", @"is", @"a", @"pen."];
NSString *separator = @" ";

NSString *result2 = @"";
for (int i=0; i<strings.count; ++i) {
    result2 = [result2 stringByAppendingString:strings[i]];
    if (i < strings.count - 1) {
        result2 = [result2 stringByAppendingString:separator];
    }
}
NSLog(@"Text: %@", result2);

Text: This is a pen.

する必要がなくなって、シンプルに書ける。

NSArray<NSString *> *strings = @[@"This", @"is", @"a", @"pen."];
NSString *separator = @" ";

NSString *result = [strings componentsJoinedByString:separator];
NSLog(@"Text: %@", result);

Text: This is a pen.

便利。Objective-C には、意外とユーティリティ的なメソッドも用意されていると知る今日この頃。

2017-02-19

Objective-C で 2 つの配列を比べた時同じ要素で最初に見つかったものを返す方法

2 つの配列がを比べて「同じ要素」があるかないか? あるなら、最初に見つかった要素は何か? を調べたいとする。

これを for 文で書くとこんな風に長いコードを書く必要が出てくる (Goto 文を使う是非は置いといて...)。

NSArray *numbers = @[@1, @2, @3, @4, @5, @6];
NSArray *targets = @[@3, @4, @9];

NSNumber *result = nil;
for (NSNumber *n in numbers) {
    for (NSNumber *m in targets) {
        if ([n isEqual:m]) {
            result = n;
            goto objectFound;
        }
    }
}
objectFound:;
NSLog(@"first object: %@", result);

first object: 3

実は Objective-C には、こういう目的に合ったメソッドが用意されている。それが firstObjectCommonWithArray:。これを使って上のコードを書き直すと、for 文が一行にまとめられる:

NSArray *numbers = @[@1, @2, @3, @4, @5, @6];
NSArray *targets = @[@3, @4, @9];

NSNumber *result = [numbers firstObjectCommonWithArray:targets];
NSLog(@"first object: %@", result);

first object: 3

もし見つからなかった場合は nil が返る。便利!

2017-02-15

Objective-C で NSArray から filter した配列を得る

配列を filter して新しい配列を得たい。Swift で言う所の、次のようなコード。

let array = [1,2,3,4,5,6]
let newArray = array.filter { $0 % 2 == 0 }

Objective-C で書こうとするとループを回すしかないのかな? なんて思ってた。こんな感じに。

NSArray *numbers = @[@1, @2, @3, @4, @5, @6];
NSMutableArray *tmp = [NSMutableArray new];
for (NSNumber *n in numbers) {
    if (n.integerValue %2 == 0) {
        [tmp addObject:n];
    }
}
NSArray *newArray = [tmp copy];
NSLog(@"even numbers: %@", newArray);
even numbers: (
    2,
    4,
    6
)

そしたら filteredArrayUsingPredicate: というメソッドがあることを知った。上のコードは次のように書ける。

NSArray *numbers = @[@1, @2, @3, @4, @5, @6];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"modulus:by:(SELF, 2) == 0"];
NSArray *evenNumbers = [numbers filteredArrayUsingPredicate:predicate];
NSLog(@"even numbers: %@", evenNumbers);
even numbers: (
    2,
    4,
    6
)

7 行のコードがたったの 2 行になった。頑張れば 1 行でも書けそう。

Swift ほどのシンプルさはないし、NSPredicate を使いこなせないといけないけれど、極めれば便利に使えそう。

modulus:by: は NSExpression.h の中に載っていた。

2017-02-04

NSArray に subArray を追加した NSArray を返す

Objective-C で NSArray に要素を追加することは出来ない。追加したければ NSMutableArray を使う。

NSArray から NSMutableArray は、mutableCopy で作れる。

NSArray *array = @[@1, @2, @3];
NSMutableArray *mArray = [array mutableCopy];
NSArray *subArray = @[@4, @5, @6];
[mArray addObjectsFromArray:subArray];
NSArray *newArray = [mArray copy];

ただし、「元の NSArray に subArray を追加した NSArray」が欲しいだけなら、mutableCopy を使う必要はない。arrayByAddingObjectsFromArray: というメソッドが使える。上のコードをarrayByAddingObjectsFromArray: を使うとこう書き直せる。

NSArray *array = @[@1, @2, @3];
NSArray *subArray = @[@4, @5, @6];
NSArray *newArray = [array arrayByAddingObjectsFromArray:subArray];

NSMutableArray を一度作らなくて良いので手間が省ける。関数型っぽく書ける点も気に行っている。

2017-01-31

NSMutableArray に subArray を追加する

Objective-C で Array (NSMutableArray) に要素を追加する時は - addObject: を使う。

NSMutableArray *arr = [NSMutableArray new];
NSNumber *item = @1;
[arr addObject:item];

では配列を追加する場合は?

ループを回しても良い。

NSArray *subArray = @[@1, @2, @3];
NSMutableArray *arr = [NSMutableArray new];
for (NSNumber *item in subArray) {
  [arr addObject:item];
}

でも、arr の変化を ReactiveCocoa などでオブザーブしてると、item を追加するたびに発火して面倒。

そこで、- addObjectsFromArray: を使う。

NSArray *subArray = @[@1, @2, @3];
NSMutableArray *arr = [NSMutableArray new];
[arr addObjectsFromArray:subArray];

一気に追加できて便利。

2017-01-20

プロパティー属性: delegate は weak, block は copy

Objective-C でクラスのプロパティとして delegate を持つ場合に、オーナーシップ属性として weak を付ける (一部の例外を除く) のは知っていたのだけど、ブロックにも weak を付けてハマった。Block の場合は weak ではなく copy を使うのね。

typedef FooBlock *(^FooBlock)(NSString *input);

@interface FooObject : NSObejct
@property (nonatomic, copy) FooBlock block;
@property (nonatomic, weak) id<FooDelegate> delegate;

...
@end

ただし、書き方は分かったけど、使いこなせてはいない。循環参照が怖いなぁ。

ref

2014-10-19

ReactiveCocoa Tokyo #rac_tokyo で LT をした

2014-09-18 (土)、五反田はfreee 社のオフィスにて開かれた ReactiveCocoa Tokyo にて LT をやってきた。

ReactiveCocoa Tokyo at freee

タイトルは「distinctUntilChanged の使いどころ」。ReactiveCocoa で基本となる RAC マクロと RACObserveの使い方から始めて mapsubscribeNext を使った書き方。循環参照を避けることができる便利な rac_liftSelector での書き直し。RACSignal を作ってシグナルを使い回す方法を一連の流れで紹介した。その後、ChatWork のライブ機能 (ビデオ・チャット機能) を例に少し込み入ったコードを書いて、問題点を提起。解決策に distinctUntilChanged を使う、という内容。

今回は初めて Mac の Keynote アプリを使ってプレゼン資料を作ってみた。今までは Goodle Slide だったので、使い勝手の小さな違いに苦しんだ。何より話の流れがまとまらなくて、かなり足ぶみした。資料が出来たのは発表当日の午前 3 時だった。5〜10 分の LT 枠なのに、資料の枚数が 20 枚になっていて、再び頭を痛めた。

本番では早口になってしまったけど、大丈夫だったかな? ReactiveCocoa の入門的な内容にもなるよう資料を組んだつもりなので、参考になったら嬉しいな。

あとがき

ReactiveCocoa 関西から約 3 か月。話すネタはなくなったかな? なんて声も聞こえたけど、懇親会ではまだ知らない ReactiveCocoa の便利なメソッドや思わぬ落とし穴の話を聞くことができた。1 時間近い大きな講演は難しいかもしれないけど、30 分くらいのトピックならまだまだザクザクとネタが残ってるんじゃないかな。

2014-10-10

Objective-C で乱数 -- arc4random_uniform

iOS の開発してて、ちょいと乱数を使いたくなった。本気な時は、メルセンヌ・ツイスターな乱数発生器を使うのだけど、今回はそこそこテスト的に使うだけで、いずれ消すコードだったので、システムが用意しているものを使った。

C だとシードを与えて rand() 関数を呼ぶのが普通。でも、Objective-C にはお手軽な乱数発生器がある。

arc4random_uniform

arc4random_uniform(N) 関数を呼ぶと、0 から N-1 の一様乱数が得られる。シードの設定は不要。サンプルはこんな感じ。

#include <stdlib.h>
...
...
int r = arc4random_uniform(64);

変数 r には 0 から 63 までの数が入る。手軽に使えるのでオススメ (同様の結果は arc4random() % N でも得られるけど、arc4random_uniform(N) の方が好ましい!)。

2014-08-09

各種プロジェクト向け .gitignore ファイル

新しいフレームワーク、新しいツールを使ってプロジェクトを開始する時、当然そのプロジェクトは git で管理するとして、.gitignore をどうするかは頭痛のタネになる。

例えば、ぼくは XCode で iOS アプリを開発しようとしているけれども、どのファイルを Git で管理すれば良いのか分からない。どのファイルを無視して良いのか分からない。そこで役に立つのが GitHub が集積している .gitignore ファイル一群。

XCode ならば Objective-C.gitignore というファイルをコピーすればいい。

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Pods/

内容充実な .gitignore ファイルが用意されている。

CocoaPods を使う場合は Pods ディレクトリーを .gitignore に含めることを勧めない、とのコメントもあり。ぼくは Pods ディレクトリーを ignore しちゃう派だけど、そこら辺は自己責任で決められたし。Pods ディレクトリーを含める・含めないについては下記記事を参照とのこと。

あとがき

ここには Objective-C の他にも、Android, Elisp, Rails, Scala, Swift, TeX と様々な言語・フレームワークへの gitignore ファイルが集まっている。gitignore ファイルをどうするか頭を悩ます時間があったら、サクッとここのファイルを使わせてもらおう。時間の節約にもなるし、勉強に繋がることもある。

2014-07-26

ReactiveCocoa 勉強会に参加した #rac_kansai

2014-07-26 (土)。はてなの京都オフィスを借りて開催された ReactiveCocoa 勉強会に参加した。

内容は Objective-C で Reactive プログラミングを行なうライブラリー ReactiveCocoa の勉強会。

LT で 10 分弱、話しをしたので資料を置く。

ReactiveCocoa では直接 Collection 系 (NSMutableArray とか NSMutableDictionary とか) を Observe できない。RACSubject を使えば大低の場合、代替の機能を提供できる、という話をした。

スライドには簡略化したコードしか書いていない。サンプル・コードは ViewController の他に ViewModel と Model を作って MVVM な作りにしてある。また、口頭でしか伝えなかった KVO と ReactiveCocoa を使った Observe のサンプル・コードも書いてある。興味のある方はどうぞ。

see also.

2014-06-03

【WWDC】iOS 8 開発者向け新機能

2014-06-03 の WWDC で Apple は開発者向けの発表を行なった。特に新 SDK はアップル・ストア始まって以来の大きなリリースになるという。新 API の数は 4,000。

TestFlight

TestFlight は開発中アプリのテスト公開用プラットホーム。Burstly 社が開発していたけど、2014 年 2 月に Apple により買収されていた。その TestFlight が Apple の正式サービスとして再開される。価格は無料。

アプリ拡張

他のアプリとの連携が可能になる? やり方はよく分からないけど、一度 iOS のセキュリティ・システムを経由する形で、アプリ間の連携が可能になるっぽい。例えば iOS 標準の「共有」項目に自分のアプリを追加したり、アクションを追加したりできる。

Notification Center に置くウィジェットの開発も、この機能を使う。

サードパーティー・キーボード

システムワイドに使えるサードパーティー・キーボードの開発。

Touch ID

指紋認証をアプリにも組み込めるようになった。アプリのログインなどに利用できる。

HomeKit

家庭のデバイスと連携するための仕組み。ライト・鍵・カメラ・ドア・温度計・プラグ・スイッチ etc. を iOS から操作できるようになる。デバイス側の開発も必要なので家電メーカーの開発を待ちしかないのかな?

Cloud Kit

iOS 用のサーバーを提供・開発に利用する仕組み。Amazon EWS や Google App Engine を使わなくても、サーバー・システムを開発できる。

Metal

OpenGL を置き換える Apple の 3D エンジン。特にゲームでオーバーヘッドへ少なくして 10 倍の速さを叩き出す。

XCode - Swift

Objective-C に代わる新しい開発言語 Swift を発表した。

Swift は Objective-C にないモダンな機能を提供する:

  • Closures
  • Generics
  • Namespaces
  • Type interface
  • Multiple return types

Swift は REPL を採用しインタラクティブな開発が可能となる。コード量の削減も大きい。

これは WWDC で出た Objective-C のサンプル・コード:

if (myDelegate != nil) {
  if ([myDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
    [myDelegate scrollViewDidScroll:myScrollView];
  }
}

このコードが Swift だと、こうなる:

myDelegate?.scrollViewDidScroll?(myScrollView)

う〜ん、すごい。サラリと説明されてたけど Autovectorizer (自動ベクトル化) もサポートするらしい。メモリー管理は GC (ガベージ・コレクション) ではなく ARC。ランタイムは Objective-C と同じ。

落ち穂拾い

  • Camera APIs (ホワイトバランス etc.)
  • PhotoKit
  • HealthKit
  • SpriteKit
  • SceneKit

盛り沢山。

2014-01-17

Objective-C の NSMutableArray の簡単な作り方

Objective-C ではサイズを変更できない配列 (NSArray) と、サイズを変更できる配列 (NSMutableArray) がある。Objective-C の参考書を読むと、Array の作り方として次のようなコードが書いてある。

NSArray* array = [[NSArray alloc] init];
NSMutableArray* mutableArray = [[NSMutableArray alloc] init];

これは本当に初歩的な書き方。Objective-C 2.0 (今の iOS 開発なら、Objective-C 2.0 がデフォールトになってる) なら、もっと簡単な Array の作り方がある。

NSArray* array = @[];

Array は大きさを変えられないので、実際のコードでは次の様にデータを入れて初期化する。

NSArray* array = @[@"foo" @"bar" @"hoge"];

Array はこんなにシンプルな書き方があるのに、MutableArray にはないものか... と諦めていたら、簡単な方法を見つけた。mutableCopy を使う。

NSMutableArray* mutableArray = [@[] mutableCopy];

Array を作って mutableCopy で mutable 化する。なんとシンプルな!!

蛇足ながら初期値を持つ場合のコードは...

NSMutableArray* mutableArray = [@[@"foo" @"bar" @"hoge"] mutableCopy];

NSMutableArray はサイズ 0 のものを作って、アイテムを push していくからあまり使わないけどね。でも、シンプルな NSMutableArray の作り方は覚えておいて損はない。

2013-09-07

Objective-C の [UIColor xxxColor] は UIColor.xxxColor と書ける

Objective-C で予約された色を使う時は UIColor クラスが使う。例えば青色ならこんな感じ。

[UIColor blueColor]

どこで知ったのか忘れたけど、色の指定方法。ドット記法でも書ける。

UIColor.blueColor

こちらの方が見た目がスマート。困るのは XCode 4.6.3 が、まだ補完機能に対応していないこと (補完に対応していないだけで、コンパイルには支障ない)。ぼくは、ドット記法な方が読み易いし、読み易い方が後でコードを読み直す時にリーダビリティが上がると考えているので、ドット記法を好む。

とはいえ、補完を使わないと思わぬタイプミスをやってしまうので、適当なタイミングで Emacs などからドット記法に書き換えるようにしている。

参考に、色の一覧を載せておく:

  • blackColor
  • whiteColor
  • grayColor
  • darkGrayColor
  • lightGrayColor
  • clearColor (透明)
  • redColor
  • blueColor
  • greenColor
  • brownColor
  • magentaColor
  • orangeColor
  • purpleColor
  • yellowColor

2013-09-03

NSMutableArray のコピー

Objective-C で今日、ちょっとハマッたのでメモ。

NSMutableArray な変数をコピーする時は、copy メソッドは使えない。使えなくはないけど、NSArray が返ってくる。ので、insert とか add とか実行すると実行エラーになる。

で、どうするかというと、mutableCopy を使う。

NSMutableArray* foo = [NSMutableArray array];
(誤) NSMutableArray* bar1 = foo.copy;
(正) NSMutableArray* bar2 = [foo mutableCopy];

NSCopying

ぼくは、今回 NSCopying のコーディングでハマった。NSCopying については、他のサイトを参照してもらうことにして、ぼくが書いたコードはこんな感じ。

- (id)copyWithZone:(NSZone *)zone {
  MYClass* clone = [super copyWithZone:zone];
  clone.foo = [_foo mutableCopyWithZone:zone];
  return clone;
}

まったく、コピーした後で addObject が通らなくなるんだからびっくりしたよ。

2013-04-03

小さな Objective-C コードを書いてみた

最初の敗北: Object 編

Objective-C入門を一読して、小さな Objective-C のソースコードを書いてみた。以下の通り:

#import <objc/Object.h>
#import <stdio.h>

@interface Point : Object
{
        int x;
}
-(id) setX :(int)x;
-(int) getX;
@end

@implementation Point
-(id) setX :(int)x
{
  self->x = x;
  return self;
}
-(int) getX {
  return x;
}
@end

int main(void)
{
  id point = [Point alloc];
  [point setX: 10];
  printf("Point X is %d\n.", [point getX]);

  return 0;
}

このコードを前エントリーの Makefile (必要部分だけ抜粋) を使ってコンパイル。

#
# Makefile for hello
#
TARGET = hello

OBJC = gcc
OBJCFLAGS = -W -Wall
LIB = -lobjc

all: $(TARGET)

$(TARGET): main.o
 $(OBJC) $(OBJCFLAGS) $^ $(LIB) -o $@

%.o: %.m
 $(OBJC) $(OBJCFLAGS) -c $< -o $@

実行結果は次の通り。Warning は出ているけど、エラーは出てない。

$ LANG=C make -k
gcc -g -W -Wall -c main.m -o main.o
main.m: In function '-[Point setX:]':
main.m:15:3: warning: local declaration of 'x' hides instance variable [enabled by default]
main.m: In function 'main':
main.m:25:3: warning: 'Point' may not respond to '+alloc' [enabled by default]
main.m:25:3: warning: (Messages without a matching method signature [enabled by default]
main.m:25:3: warning: will be assumed to return 'id' and accept [enabled by default]
main.m:25:3: warning: '...' as arguments.) [enabled by default]
gcc -g -W -Wall main.o -lobjc -o hello

Compilation finished at Wed Apr  3 12:15:28

で、これを実行すると失敗。

$ ./hello
Segmentation fault (コアダンプ)

次のトライ: NSObject 編

色々試して行き詰まったので、Ubuntu LinuxでObjective-C - Tomute’s Notes の記事を参考に NSObject を使う方向に方針転換。

インストール

NSObject を使うためのインストールを実行

$ sudo apt-get install libgnustep-base-dev
$ sudo apt-get install gnustep
$ sudo apt-get install gnustep-devel
Makefile の編集

OBJCFLAGSLIBS に NSObject 用の設定を追記。面倒なので全部コピペしちゃう。

#
# Makefile for hello
#
TARGET = hello

OBJC = gcc
OBJCFLAGS = -I/usr/include/GNUstep -fconstant-string-class=NSConstantString -W -Wall
LIB = -lobjc -lgnustep-base

all: $(TARGET)

$(TARGET): main.o
 $(OBJC) $(OBJCFLAGS) $^ $(LIB) -o $@

%.o: %.m
 $(OBJC) $(OBJCFLAGS) -c $< -o $@

#
# clean
#
RM = rm -f

clean:
 $(RM) *~
 $(RM) *.o
distclean: clean
 $(RM) $(TARGET)

ソースコードの編集

こちらの変更は小さい。#import <objc/Object.h>#import <Foundation/NSObject.h> に変えて、スーパークラス ObjectNSObject に変更する。

これでコンパイルが通るはず... と思ったら、setX メソッドでエラー。

self->x = x;

このコードがインスタンス変数 x を遮蔽しているという。Object を使った時にも同じ文言が出たけど、その時は「エラー」じゃなくて「警告」だったのに... 何故?

とりあえず、ベタな修正をかけて、ハイ完成。

#import <Foundation/NSObject.h>
#import <stdio.h>

@interface Point : NSObject
{
  int x;
}
-(id) setX :(int)x_;
-(int) getX;
@end

@implementation Point
-(id) setX :(int)x_
{
  x = x_;
  return self;
}
-(int) getX {
  return x;
}
@end

int main(void)
{
  id point = [Point alloc];
  [point setX: 10];
  printf("Point X is %d\n.", [point getX]);

  return 0;
}

これでコンパイルして実行すると、めでたし Objective-C のプログラムが実行できた。

$ ./hello
Point X is 10

あとがき

もしかして、Object を使ってた時も self がいけなかったんじゃないかと、NSObject と同じ様にコードを修正してみたものの、再び Segmentation fault になった。何故? 何が足りないの?

あと、self は使えないの? 色々悶々と悩みながら Objective-C のプログラミングを勉強中。ああ、なんか釈然としない。

初めての Objective-C (in Ubuntu Linux)

MacBook Air を注文したことだし、Objective-C のプログラミングでもやってみようかと手を出した。コンパイル環境は Ubuntu Linux 12.10 (MacBook Air はまだ届いていない)。基本、C の拡張ということで甘く見てた。そして一手目からコケた。

  • 拡張子は何?
  • コンパイラーは何?
  • Makefile はどう書くの?
  • 必要なライブラリーは?

Hello, World を出力するまでを記事にする。

インストール

libc6-dev をインストールするために build-essential パッケージを、Objective-C 用のライブラリーをインストールするために gobjc パッケージをインストールする。

$ sudo apt-get install build-essential
$ sudo apt-get install gobjc

ソースコード

  • #include の代わりに #import を使う
  • Objective-C では objc/Object.h のインポートが必須 (Cocoa 開発の場合を除く)

#import は #include と違って二重読み込みをしない仕様とのこと。

Hello, World を出力するプログラムはこちら。

#import <objc/Object.h>
#import <stdio.h>

int main(void)
{
  printf("Hello, World!\n");

  return 0;
}

main 文の引数を空にすべきか、void にすべきか悩む... ANSI C の上位互換なら void にすべきか? これを拡張子 .m で保存する。

Makefile

GNU Makefile では、Objective-C をデフォールトでサポートしていないのね。implicit variables や implicit rules が使えなくて驚いた。

Objective-C のコンパイラーは gcc を使えば良いらしいけど、変数名を CCC とするか OBJC にするか二通りの流儀があるらしい。CCC は昔、C++ のコンパイラー変数として使われていたこともあるので、後者を選ぶ。

必須ライブラリー objc を呼ぶことを忘れずに書いた Makefile (最小) は以下の通り:

#
# Makefile for hello
#
TARGET = hello

OBJC = gcc
OBJCFLAGS = -W -Wall
LIB = -lobjc

all: $(TARGET)

$(TARGET): main.o
 $(OBJC) $(OBJCFLAGS) $^ $(LIB) -o $@

%.o: %.m
 $(OBJC) $(OBJCFLAGS) -c $< -o $@

#
# clean
#
RM = rm -f

clean:
 $(RM) *~
 $(RM) *.o
distclean: clean
 $(RM) $(TARGET)

最後に make コマンド実行でコンパイル終了。

$ make
gcc -W -Wall -c main.m -o main.o
gcc -W -Wall main.o -lobjc -o hello

あとがき

今回のコードは、Objective-C のコードを一行も書いていない。C のソースコードを、Objective-C のやり方に則ってコンパイルしただけ。まだまだ勉強することは多い。

調べてると、Objective-C++ とか Objective-C 2.0 とか言語が進化してるし、gcc は事実上 GNUstep 専用と化し、Mac では LLVM ベースにシフトしているとか。一歩一歩勉強しよ。

参考記事