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 のプログラミングを勉強中。ああ、なんか釈然としない。

No comments:

Post a Comment