Objective-Cは、1980年代にブラッド・コックスによって作られた、動的メッセージディスパッチを備えたプログラミング言語です。AppleはNeXTSTEPの主要言語として、その後iOS SDKの主要言語としてObjective-Cを採用しました。Programming With Objective-C — メッセージ構文とメモリ管理の入門。
重要ポイント
Objective-Cは、Smalltalkスタイルのオブジェクト指向プログラミング機能でCを拡張するプログラミング言語です。Objective-CコードはLLVMまたはGCCを介してネイティブマシンコードにコンパイルされ、Cとの完全な後方互換性を維持します — あらゆるCコードはObjective-Cで有効です。
Appleは1997年にNeXT(Objective-Cとともに)を買収しました。この言語はmacOSとiOSのフレームワークであるCocoaとCocoa Touchの基盤となりました。2014年以降、AppleはSwiftを代替言語として推進していますが、Objective-Cはレガシープロジェクトや一部のシステムフレームワークにとって依然として極めて重要です。Apple(WWDC 2024)によると、App Storeのアプリの約35%が今もObjective-Cコードを含んでいます。
主要な特徴は動的ランタイムです。メソッド呼び出しがコンパイル時に解決されるSwiftとは異なり、Objective-Cはobjc_msgSend関数を介して実行時にメッセージを送信します。これにより、メソッドの実行時オーバーライド(method swizzling)、クラスの動的追加、存在しないセレクターに対するforward invocationの使用が可能になります。
あらゆるCコードはObjective-Cで有効です。オブジェクト指向拡張は、クラス(@interface/@implementation)、カテゴリ、プロトコル(@protocol)、動的型付け(id)を追加します。ファイルの拡張子は.m(実装)と.h(ヘッダー)です。
メッセージ構文がObjective-CとC系言語の主な違いです。object.method(argument)の代わりに[object method:argument]を使用します。各メッセージはobjc_msgSendを通過し、実行時に動的にメソッドの実装を検索します。
// 名前付きパラメータを持つメッセージ構文
NSString *greeting = [NSString stringWithFormat:@"Hello, %@", name];
// ネストされたメッセージ
NSArray *sortedArray = [[array sortedArrayUsingSelector:@selector(compare:)] copy];
// イントロスペクションによる型チェック
if ([object isKindOfClass:[UIView class]]) {
UIView *view = (UIView *)object;
view.backgroundColor = [UIColor redColor];
}動的ディスパッチにより、実行時のメソッドオーバーライド(method swizzling)が可能です — 強力だが危険な技法です。例えば、AFNetworkingやAspectsなどのフレームワークはURLSession呼び出しをインターセプトするためにswizzlingを使用します。Appleは警告しています:誤った使用でswizzlingはシステムフレームワークを壊す可能性があります。
カテゴリは、継承やソースコードへのアクセスなしに既存のクラス(NSStringやUIViewなどのシステムクラスを含む)にメソッドを追加できるObjective-Cのユニークな機能です。カテゴリは@interface ClassName (CategoryName)を使用して宣言します。
// UIColor+Hex.hファイル — UIColorのカテゴリ
@interface UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex;
@end
// UIColor+Hex.mファイル — 実装
@implementation UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex {
CGFloat r = ((hex >> 16) & 0xFF) / 255.0;
CGFloat g = ((hex >> 8) & 0xFF) / 255.0;
CGFloat b = (hex & 0xFF) / 255.0;
return [self colorWithRed:r green:g blue:b alpha:1.0];
}
@end拡張(Extensions)(Class Extension)は、名前なしで.mファイルに宣言される特別な種類のカテゴリです:@interface ClassName ()。カテゴリとは異なり、拡張はメソッドだけでなくivar(インスタンス変数)やプロパティも追加できます。拡張は外部モジュールから内部APIを隠すために使用されます。
ブロックは、外部スコープから変数をキャプチャするObjective-Cの無名関数です。ブロック構文:^(int x) { return x * 2; }。ブロックはUIKitのコールバックハンドラ、Grand Central Dispatchの非同期タスク、NSArray/NSDictionaryコレクションの関数型操作で使用されます。
// ブロック型宣言
typedef void (^CompletionBlock)(BOOL success, NSError *error);
// パラメータとしてのブロック
- (void)fetchDataWithCompletion:(CompletionBlock)completion {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL result = [weakSelf processData];
if (completion) {
completion(result, nil);
}
});
}ブロックのメモリ管理は極めて重要です。ブロックはselfを強参照でキャプチャし、直接使用するとretain cycleを引き起こします。解決策は__weak typeof(self) weakSelf = self、続いてブロック内でのチェックです。この問題はSwiftではcapture lists [weak self]によって完全に解決されています。
Objective-CはMRC(Manual Reference Counting)からARC(Automatic Reference Counting)へと進化しました。MRCでは、開発者は手動でretain(カウンター増加)、release(減少)、autorelease(遅延解放)を呼び出していました。これらの呼び出しのエラーはメモリリークやダングリングポインタによるクラッシュを引き起こしていました。
| 操作 | MRC | ARC |
|---|---|---|
| オブジェクト作成 | [[Object alloc] init] | [[Object alloc] init] |
| 参照保持 | [object retain] | 自動 |
| 解放 | [object release] | 自動 |
| 自動解放 | [object autorelease] | 自動(不要) |
| 弱参照 | __weakは存在しなかった | __weak(自動nil) |
ARCはXcode 4.2とLLVM 3.0(2011)で導入されました。コンパイラはオブジェクトのライフタイムを分析し、コンパイル時に自動的にretain/releaseを挿入します。ARCはガベージコレクションではありません — 自動挿入を伴う静的解析です。Objective-C ARCはSwift ARCと互換性があります:どちらもランタイムレベルで同じ参照カウントシステムを使用します。
1つのプロジェクトでObjective-CとSwiftを一緒に使用することは、レガシープロジェクトでは一般的なプラクティスです。AppleはBridging Headerを提供しています — SwiftがObjective-Cクラスを認識し、Objective-CがNSObjectを継承するSwiftクラスを認識するための自動生成ファイルです。
// ProjectName-Bridging-Header.h
// Swiftはこれらのヘッダーを自動的に認識します
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"Objective-CからSwiftへの移行は段階的なプロセスです。新しいファイルはSwiftで書き、古いファイルは徐々にリファクタリングします。Bridging Headerは、Objective-Cプロジェクトに最初のSwiftファイルを追加したときに自動生成されます。逆方向の可視性(ObjC → Swift)のために、Xcodeは@objcでマークされたSwiftクラスの@interface宣言を含む<ProjectName>-Swift.hファイルを生成します。
// Objective-Cから見えるSwiftクラス
@objc class SwiftRouter: NSObject {
@objc func navigateToProfile(userId: Int) {
// 実装
}
}制限事項:Swiftの値型(struct、enum)はObjective-Cから直接見えません — @objc付きのクラスでラップする必要があります。SwiftのジェネリクスはObjective-Cからのアクセスが制限されています。推奨されるアプローチは、新しいコードをSwiftで書き、既存のObjective-Cコードは対応する機能を変更する場合にのみリファクタリングすることです。
Swiftに対するObjective-Cの主な利点はランタイムへの完全なアクセスです。Method swizzling(実行時のメソッド実装の置き換え)により、継承なしでシステムメソッドをオーバーライドできます。AspectsやJRSwizzleなどのライブラリは、AOP(アスペクト指向プログラミング)— 監視、分析、ロギングにこの機能を使用します。
Forward invocationは別のランタイム機能です:オブジェクトがセレクターに応答しない場合、システムはforwardInvocation:を呼び出し、メッセージを別のオブジェクトに転送できます。これはObjective-C(NSProxy)のプロキシパターンの基礎であり、遅延初期化や分散オブジェクトに使用されます。
Appleは新しいコードでのランタイムトリックの使用を最小限に抑え、Swiftの静的型付けを優先することを推奨しています。ただし、レガシープロジェクトでは、objc_msgSend、method_exchangeImplementations、objc_getAssociatedObjectの知識が既存のコードベースのメンテナンスに必要です。
Objective-Cはgetter/setter付きのivarに対するプロパティをシンタックスシュガーとしてサポートしています。atomic/nonatomic、strong/weak/copy、readonly/readwrite、assign/retainの修飾子がメモリ動作とスレッドセーフティを決定します。Key-Value Observing(KVO)はランタイムに組み込まれたプロパティ変更監視メカニズムです:任意のオブジェクトがaddObserverを介して別のオブジェクトのプロパティ変更を購読できます。
よくある質問
メソッド呼び出しは[object selector:argument]のように見えます。メッセージはobjc_msgSendを通過し、ランタイムで動的に実装を見つけます。セレクターはメソッド名(@selector(methodName))であり、関数ポインタではありません。これによりswizzlingとforward invocationが可能になります。
カテゴリ(@interface ClassName (Name))は継承なしで任意のクラス(システムクラスを含む)にメソッドを追加します。拡張(@interface ClassName ())は.mファイルで宣言され、プロパティとivarsを追加できます。カテゴリはivarsを追加できませんが、拡張は追加できます。
ブロックは^(パラメータ) { 本体 }構文の無名関数で、コンテキストから変数をキャプチャします。C++のラムダやSwiftのクロージャに類似しています。selfをキャプチャする際のretain cycleを防ぐために__weakが必要です。UIKit、GCD、Foundationで使用されます。
MRCは手動参照カウント:プログラマーがretain、release、autoreleaseを呼び出します。ARCは自動:コンパイラが静的解析に基づいてretain/releaseを挿入します。ARCはGCではありません — カウンターがゼロになるとオブジェクトは即座に解放されます。ARCは__weakと__strong修飾子をサポートします。
はい、Bridging Headerを介して可能です。Swiftはこのヘッダーを通じてObjective-Cを認識し、Objective-Cは<ProjectName>-Swift.hを通じてSwiftを認識します。SwiftクラスはNSObjectを継承し、@objcでマークする必要があります。SwiftのstructとenumはObjective-Cから直接見えません。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。