Tips

Objective-C NSArray 配列 【初級編 第20回】

配列のNSArray

配列

前回までObjective-Cにおける文字列の取り扱いについて取り上げてきました。
ここまでのソースコードでは、一人分のデータを処理してましたが複数人のデータを扱う場合どのように管理すればよいでしょうか。
以下のようにPersonオブジェクトを人数分作成してもかまいませんが、データを扱うには不便です。

Person teacher1,teacher2,teacher3

これでは人数が増えてくるとその分の変数を宣言していくことになります。
同じデータ型ものをひとまとめにして扱えれば操作が楽になります。そこで使用されるのが配列となります。
配列を使用すると中に入っているデータを番号を使用して取り出すことができます。配列の3番目のデータといった具合です。
この番号のことを「添え字」といいます。
CやJavaを触ったことのある方ならご存知と思いますがこの添え字については注意しなければならないことがあります。
添え字は「0」からスタートするということです。
4個のデータが格納されている配列があった場合、先頭のデータの添え字は「0」となります。4つ目のデータであれば「3」
ということになります。このとき「4」と間違えると確保していない領域を参照するということになり実行時にエラーとなります。

Objective-Cで配列を扱うときに使用されるクラスとしてNSArrayというクラスがあります。
このクラスは前回の最後に述べたように不変と可変の対になっているクラスの1つです。
不変の場合はNSArrayを使用し、可変の場合はNSMutableArrayを使用します。

NSArrayクラス

NSArrayクラスは「immutable」なクラスです。インスタンス化したときに作られた配列の内容を変更することができません。
NSArrayクラスをオブジェクト化するには以下のメソッドを使用します。(これ以外にもあります。)

+ (id) arrayWithObjects: (id)firstObject, ...;
- (id) initWithObjects: firstObject, ...;

「arrayWithObjects」の方はクラスメソッドですので、インスタンス化せずに使用することが可能です。
「initWithObjects」の方はインスタンスメソッドですので、インスタンス化しなければ使用できません。
両方のメソッドとも引数は複数つけられるようになっていますが、引数の最後には「nil」を指定しなければなりません。
どちらのメソッドも戻り値はid型となりますが違いがあります。
「arrayWithObjects」の方は自動解放プールに登録されますが、initWithObjectsの方は自分で自動解放プールに登録するか
「release」メッセージを使用して解放するといった処理が必要になります。
では中に入っているデータの所有権はどうなるのかというとNSArrayオブジェクトが要素の所有者となります。
NSArrayオブジェクトが解放されるときには、その内部のデータも解放処理が行われます。

これらのメソッドで作成した配列にアクセスするには以下のメソッドを使用します。

- (id) objectAtIndex: (NSUInteger)index;

引数の「index」には添え字を指定します。そうすると指定した添え字の部分のデータが戻り値として返ってきます。
上にも書いたように添え字は「0」からスタートするため、範囲外の値を指定しないように注意した下さい。

配列内にどれだけのデータが入っているのか(個数)を調べてプログラム内で使用することがあります。
そういったときに配列長を調べるメソッドとして以下のものがあります。

- (NSUInteger) count;

戻り値が配列内の要素数となります。

では実際に使用してみましょう。

コードで確認

今回はNSArrayを使用することにして実装してみましょう。これまでのコードもおさらいがてら表示してみます。
ここまで作成したファイルは「Bmi.h」「Bmi.m」「Manage.m」「Manage.h」「Person.m」「Person.h」「main.m」でした。
Bmi.h

#import <Foundation/NSObject.h>

@interface Bmi:NSObject

//BMI値を計算
+(double)calcBmi:(double)weight height:(double)height;
//適正体重を計算
+(double)calcProperWeight:(double)height;

@end

BMIを計算するクラスです。
NSObjectを継承してクラスを作成しています。メソッド定義の「+」はクラスメソッドを表しています。
今のところインスタンス化する必要がないからですね。
特に以前から変更していません。

Bmi.m

#import "Bmi.h"

@implementation Bmi
    +(double)calcBmi:(double)weight height:(double)height{
        return weight/(height * height);
    }
    +(double)calcProperWeight:(double)height{
        return height * height * 22;
    }
@end

こちらは実装部分ですね。注意点は定義とシグネチャを一緒にしておかないと
いけないというくらいですね。

Manage.h

#import <Foundation/NSObject.h>
#import "Person.h"

@interface Manage:NSObject
{
    Person *person;
}
-(Person*)person;
-(void)setPerson:(Person*)p;
-(void)showBestPerson;
@end

ベスト体重のユーザを管理するクラスですね。こちらはインスタンス変数を作成しています。「person」ですね。
インスタンス変数にアクセスする場合は、クラスメソッドは使用できません。

Manage.m

#import <Foundation/Foundation.h>
#import <math.h>
#import "Manage.h"
#import "Bmi.h"

@implementation Manage
-(Person*)person{
    return person;
}
-(void)setPerson:(Person*)newPerson{
    double num;
    if(person!=nil){
        num = fabs(22 - [Bmi calcBmi:[person weight] height:[person height]]) -
            fabs(22 - [Bmi calcBmi:[newPerson weight] height:[newPerson height]]);
        if( num > 0){
            [person release];
            person=newPerson;
            [person retain];
        }
    }else{
        person=newPerson;
        [person retain];
  }
}
-(void)showBestPerson
{
    printf("Best Person is %sn",[[person name] UTF8String]);
    printf("weight:%2.1fn",[person weight]);
    printf("height:%2.2fn",[person height]);
    printf("Bmi:%2.1fn",[Bmi calcBmi:[person weight] height:[person height]]);
}
-(void)dealloc{
    [person release];
    [super dealloc];
}
@end

実装部分です。Personオブジェクト自体はmain内で作成されているのでメインで解放されるとこまるので「retain」で
所有権を得ています。
最後にオブジェクトが解放されるときに呼び出されるdeallocでインスタンス変数の解放処理を行ってます。

Person.h

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

@interface Person:NSObject
{
    //属性を表す
    double height;
    double weight;
    NSString *name;
}

//アクセサ
-(double)height;
-(void)setHeight:(double)personHeight;
-(double)weight;
-(void)setWeight:(double)personWeight;
-(NSString*)name;
-(void)setName:(NSString*)personName;

//イニシャライザ
-(id)initWithWeight:(double)personWeigth height:(double)personHeight;
-(id)initWithWeight:(double)personWeight height:(double)personHeight name:(NSString*)personName;
@end

名前と体重、身長を持った人を表すためのクラスです。
名前は変更することがないだろうということで今回はNSStringクラスを使用しています。

TechProjin 開発系基礎講座 連載リンク

基礎からPHPWEBアプリ解発を学ぶなら・・
PHP基礎 連載

AIなどで注目急上昇!これから学ぶならPython!!
独学で学ぶ-pythonプログラミング 連載

汎用性◎ 定番プログラミング言語JAVA
Java基礎講座 連載

Recent News

Recent Tips

Tag Search