Objective-C

#21
TIOBE#34
PYPL#10
GitHub#21
RedMonk#17
IEEESpectrum#27
JetBrains#20
プログラミング言語オブジェクト指向iOS開発macOS開発Appleシステム開発

プログラミング言語

Objective-C

概要

Objective-Cは、C言語にSmalltalk風のオブジェクト指向機能を追加したプログラミング言語です。

詳細

Objective-Cは1980年代初期にBrad Cox氏によって開発されたプログラミング言語で、C言語をベースにSmalltalkのメッセージパッシング方式を組み合わせたオブジェクト指向言語です。Apple社によってNeXTSTEP、そして後のmacOSとiOSの主要開発言語として採用され、長年にわたってAppleプラットフォームの標準的な開発言語として使用されました。現在はSwiftにその座を譲りつつありますが、膨大な既存コードベースとライブラリがObjective-Cで構築されており、レガシーシステムの保守や既存プロジェクトとの互換性において重要な役割を果たしています。

書き方の例

Hello World

// 基本的な出力
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"Hello, World!");
        
        // 変数を使った出力
        NSString *message = @"こんにちは、Objective-C!";
        NSLog(@"%@", message);
        
        // フォーマット文字列を使った出力
        NSString *name = @"太郎";
        NSInteger age = 25;
        NSLog(@"私の名前は%@で、%ld歳です。", name, (long)age);
    }
    return 0;
}

変数とデータ型

// プリミティブ型
NSInteger intValue = 42;
NSUInteger unsignedValue = 100;
CGFloat floatValue = 3.14f;
BOOL boolValue = YES;

// オブジェクト型
NSString *text = @"文字列";
NSNumber *numberObject = @(42);
NSArray *array = @[@"要素1", @"要素2", @"要素3"];
NSDictionary *dictionary = @{
    @"key1": @"value1",
    @"key2": @"value2"
};

// 可変オブジェクト
NSMutableString *mutableText = [NSMutableString stringWithString:@"初期値"];
[mutableText appendString:@" 追加文字列"];

NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:@"A", @"B", nil];
[mutableArray addObject:@"C"];

NSLog(@"整数: %ld", (long)intValue);
NSLog(@"文字列: %@", text);
NSLog(@"配列の要素数: %lu", (unsigned long)[array count]);

条件分岐

// 基本的なif文
NSInteger score = 85;
NSString *grade;

if (score >= 90) {
    grade = @"A";
} else if (score >= 80) {
    grade = @"B";
} else if (score >= 70) {
    grade = @"C";
} else {
    grade = @"D";
}

NSLog(@"得点: %ld, 評価: %@", (long)score, grade);

// BOOL値での条件分岐
NSInteger age = 20;
BOOL hasLicense = YES;

if (age >= 18 && hasLicense) {
    NSLog(@"運転できます");
} else if (age >= 18) {
    NSLog(@"免許を取得してください");
} else {
    NSLog(@"18歳になってから免許を取得してください");
}

// switch文
typedef NS_ENUM(NSInteger, DayOfWeek) {
    Monday = 1,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
};

DayOfWeek today = Wednesday;
switch (today) {
    case Monday:
    case Tuesday:
    case Wednesday:
    case Thursday:
    case Friday:
        NSLog(@"平日です");
        break;
    case Saturday:
    case Sunday:
        NSLog(@"週末です");
        break;
}

配列と辞書の操作

// 配列の操作
NSArray *fruits = @[@"りんご", @"バナナ", @"オレンジ"];
NSLog(@"最初の果物: %@", [fruits firstObject]);
NSLog(@"果物の数: %lu", (unsigned long)[fruits count]);

// 配列の要素を順番に処理
for (NSString *fruit in fruits) {
    NSLog(@"果物: %@", fruit);
}

// インデックスを使った処理
for (NSUInteger i = 0; i < [fruits count]; i++) {
    NSLog(@"インデックス %lu: %@", (unsigned long)i, fruits[i]);
}

// 可変配列
NSMutableArray *mutableFruits = [NSMutableArray arrayWithArray:fruits];
[mutableFruits addObject:@"ぶどう"];
[mutableFruits insertObject:@"いちご" atIndex:1];

// 辞書の操作
NSDictionary *person = @{
    @"name": @"田中太郎",
    @"age": @30,
    @"city": @"東京"
};

NSLog(@"名前: %@", person[@"name"]);
NSLog(@"年齢: %@", person[@"age"]);

// 辞書のキーと値を順番に処理
for (NSString *key in person) {
    NSLog(@"%@: %@", key, person[key]);
}

// 可変辞書
NSMutableDictionary *mutablePerson = [NSMutableDictionary dictionaryWithDictionary:person];
mutablePerson[@"job"] = @"エンジニア";

ループ処理

// for-in文
NSArray *numbers = @[@1, @2, @3, @4, @5];
for (NSNumber *number in numbers) {
    NSInteger value = [number integerValue];
    NSLog(@"数値: %ld, 2倍: %ld", (long)value, (long)(value * 2));
}

// 従来のfor文
for (NSInteger i = 1; i <= 5; i++) {
    NSLog(@"%ldの2乗は%ldです", (long)i, (long)(i * i));
}

// while文
NSInteger count = 0;
while (count < 5) {
    NSLog(@"カウント: %ld", (long)count);
    count++;
}

// do-while文
NSInteger counter = 0;
do {
    NSLog(@"実行回数: %ld", (long)(counter + 1));
    counter++;
} while (counter < 3);

クラスの定義と使用

// ヘッダーファイル (.h)
@interface Car : NSObject

@property (nonatomic, strong) NSString *make;
@property (nonatomic, strong) NSString *model;
@property (nonatomic, assign) NSInteger year;
@property (nonatomic, assign) NSInteger mileage;

- (instancetype)initWithMake:(NSString *)make model:(NSString *)model year:(NSInteger)year;
- (void)driveDistance:(NSInteger)distance;
- (NSString *)getInfo;

@end

// 実装ファイル (.m)
@implementation Car

- (instancetype)initWithMake:(NSString *)make model:(NSString *)model year:(NSInteger)year {
    self = [super init];
    if (self) {
        _make = make;
        _model = model;
        _year = year;
        _mileage = 0;
    }
    return self;
}

- (void)driveDistance:(NSInteger)distance {
    self.mileage += distance;
    NSLog(@"%ldkm 運転しました。総走行距離: %ldkm", (long)distance, (long)self.mileage);
}

- (NSString *)getInfo {
    return [NSString stringWithFormat:@"%ld年式 %@ %@", (long)self.year, self.make, self.model];
}

@end

// 使用例
Car *myCar = [[Car alloc] initWithMake:@"トヨタ" model:@"プリウス" year:2022];
NSLog(@"%@", [myCar getInfo]);
[myCar driveDistance:50];
[myCar driveDistance:30];

プロトコル(インターフェース)

// プロトコル定義
@protocol Drawable <NSObject>
@required
- (void)draw;
- (CGSize)getSize;

@optional
- (void)setColor:(UIColor *)color;
@end

// プロトコルを実装するクラス
@interface Circle : NSObject <Drawable>
@property (nonatomic, assign) CGFloat radius;
@end

@implementation Circle

- (void)draw {
    NSLog(@"半径 %.2f の円を描画", self.radius);
}

- (CGSize)getSize {
    CGFloat diameter = self.radius * 2;
    return CGSizeMake(diameter, diameter);
}

- (void)setColor:(UIColor *)color {
    NSLog(@"円の色を設定");
}

@end

カテゴリ(既存クラスの拡張)

// NSStringカテゴリの定義
@interface NSString (Utilities)
- (BOOL)isValidEmail;
- (NSString *)reverseString;
@end

@implementation NSString (Utilities)

- (BOOL)isValidEmail {
    NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}";
    NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
    return [emailTest evaluateWithObject:self];
}

- (NSString *)reverseString {
    NSMutableString *reversedString = [NSMutableString string];
    for (NSInteger i = [self length] - 1; i >= 0; i--) {
        [reversedString appendString:[NSString stringWithFormat:@"%C", [self characterAtIndex:i]]];
    }
    return reversedString;
}

@end

// 使用例
NSString *email = @"[email protected]";
NSLog(@"有効なメール: %@", [email isValidEmail] ? @"YES" : @"NO");

NSString *text = @"Hello";
NSLog(@"逆順: %@", [text reverseString]);

特徴的な機能

メモリ管理(ARCとマニュアル)

// ARC(Automatic Reference Counting)使用時
@property (nonatomic, strong) NSString *strongProperty;  // 強参照
@property (nonatomic, weak) id<SomeDelegate> weakProperty;  // 弱参照
@property (nonatomic, copy) NSString *copyProperty;  // コピー

// ブロック(クロージャ)
typedef void (^CompletionBlock)(BOOL success, NSError *error);

- (void)performTaskWithCompletion:(CompletionBlock)completion {
    // 非同期処理
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 何らかの処理
        BOOL success = YES;
        NSError *error = nil;
        
        dispatch_async(dispatch_get_main_queue(), ^{
            if (completion) {
                completion(success, error);
            }
        });
    });
}

KVO(Key-Value Observing)

// オブザーバーの登録
[self addObserver:self 
       forKeyPath:@"someProperty" 
          options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld 
          context:nil];

// 変更通知の受信
- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary<NSKeyValueChangeKey,id> *)change 
                       context:(void *)context {
    if ([keyPath isEqualToString:@"someProperty"]) {
        NSLog(@"プロパティが変更されました: %@ -> %@", 
              change[NSKeyValueChangeOldKey], 
              change[NSKeyValueChangeNewKey]);
    }
}

// オブザーバーの削除(重要)
- (void)dealloc {
    [self removeObserver:self forKeyPath:@"someProperty"];
}

バージョン

バージョン ステータス 主要な特徴 リリース年
Objective-C 2.0 現行 プロパティ、ガベージコレクション 2007
Objective-C 1.0 レガシー 基本的なオブジェクト指向機能 1988

参考ページ

公式ドキュメント

学習リソース

開発ツール

  • Xcode - Apple公式IDE
  • CocoaPods - 依存関係管理ツール
  • Carthage - 軽量な依存関係管理ツール