iOS開発者ガイド:Objective-CからLearningSwiftまで
公開: 2022-03-112008年、AppleはiPhoneSDK2.0を発表してリリースしました。 このイベントはソフトウェア開発に新たな革命をもたらし、新しい種類の開発者が誕生しました。 彼らは現在、iOS開発者として認識されています。
これらの開発者の多くはこれまでObjective-Cを使用したことがなく、それがAppleが彼らに投げかけた最初の課題でした。 なじみのない構文と手動のメモリ管理にもかかわらず、それは大成功を収め、AppStoreに数万のアプリを追加するのに役立ちました。 Appleは、リリースごとにObjective-Cを継続的に改善し、ブロックとリテラルを追加し、自動参照カウントによるメモリ管理を簡素化し、最新のプログラミング言語を示す他の多くの機能を提供しました。
そして、Objective-Cの改善と取り組みを6年間行った後、Appleは開発者に別の課題を投げかけることにしました。 繰り返しになりますが、iOS開発者は新しいプログラミング言語であるSwiftを学ぶ必要があります。 Swiftは、Objective-CとCの両方との相互作用を維持しながら、安全でないポインター管理を削除し、強力な新機能を導入します。
Swift 1.0はすでに安定した強力な開発プラットフォームであり、今後数年間で興味深い方法で進化することは間違いありません。 これは明らかにiOS開発の未来であるため、この新しい言語の探索を開始する絶好の機会です。
このチュートリアルの目的は、Objective-C開発者に新しいSwift言語機能の概要を説明し、次のステップに進み、日常業務にSwiftを採用し始めるのに役立つことです。 私はObjective-Cの説明にあまり時間をかけず、iOS開発に精通していることを前提としています。
SwiftとObjective-Cを試す
Swiftの探索を開始するには、App StoreからXCodeをダウンロードし、実験用の遊び場を作成するだけです。 この記事で言及されているすべての例は、この方法で行われます。
AppleのSwiftホームページは、Swiftプログラミングを学ぶための最良のリファレンスです。 あなたはそれがかけがえのないものであることに気付くでしょう、そしてあなたがSwiftの開発に完全に慣れるまで、私はあなたが頻繁にここに戻ってくると信じています。
変数と定数
Swiftでの変数の宣言は、 var
キーワードを使用して行われます。
var x = 1 var s = "Hello"
2つの変数x
とs
が異なるタイプであることに気付くでしょう。 x
は整数で、 s
は文字列です。 Swiftはタイプセーフな言語であり、割り当てられた値から変数タイプを推測します。 コードを読みやすくしたい場合は、オプションで変数の型に注釈を付けることができます。
var y: Int y = 2
定数は似ていますが、 var
の代わりにlet
を使用して宣言します。 定数の値はコンパイル時に知る必要はありませんが、値を1回だけ割り当てる必要があります。
let c1 = 1 // Constant known at compile time var v = arc4random() let c2 = v // Constant known only at run time
それらの名前が示すように、それらは不変であるため、次のコードはコンパイル時エラーを引き起こします。
let c = 1 c = 3 // error
他のタイプも定数として宣言できます。 たとえば、次のコードは配列を定数として宣言しており、要素のいずれかを変更しようとすると、Swiftコンパイラはエラーを報告します。
var arr2 = [4, 5, 6] arr2[0] = 8 print (arr2) // [8, 5, 6] let arr = [1, 2, 3] a[0] = 5 // error
オプション
定数は宣言時に初期化する必要があり、変数は使用前に初期化する必要があります。 では、Objective-C nil
に相当するものはどこにありますか? Swiftではオプションの値が導入されています。 オプションの値は、値を持つことも、 nil
にすることもできます。 次のコードを見ると、 x
に2014
のOptional
値が割り当てられていることがわかります。 これは、Swiftコンパイラがx
もnil
である可能性があることを認識していたことを意味します。
var s = "2014" var x = s.toInt() print(x) // Optional(2014)
このコードに変更を加え、値"abc"
をs
に割り当てると、整数に変換できなくなり、 x
がnil
になっていることがわかります。
var s = "abc" var x = s.toInt() print(x) // nil
toInt()
関数の戻り型はInt?
、これはオプションのIntです。 x
で標準関数を呼び出してみましょう:
var x = "2014".toInt() print(x.successor()) // error
x
はオプションであり、nilになる可能性があるため、コンパイラはエラーを通知します。 最初にx
をテストし、 successor
関数がnil
値ではなく、実数で呼び出されることを確認する必要があります。
var x = "2014".toInt() if x != nil { print(x!.successor()) // 2015 }
感嘆符(!)を追加してx
をアンラップする必要があることに注意してください。 x
に値が含まれていることが確認できたら、それにアクセスできます。 そうしないと、ランタイムエラーが発生します。 また、Swiftがオプションのバインディングと呼んでいることを実行して、オプションを非オプションの変数に変換することもできます。
let x = "123".toInt() if let y = x { print(y) }
if
ステートメントのコードは、 x
に値がある場合にのみ実行され、 y
に割り当てられます。 y
をアンラップする必要はないことに注意してくださいx
はnil
ではないことがわかっているため、そのタイプはオプションではありません。
オプションとオプションのチェーンなどの優れた機能の詳細については、AppleのSwiftチュートリアルを確認してください。
文字列補間
Objective-Cでは、文字列のフォーマットは通常、 stringWithFormat:
メソッドを使用して行われます。
NSString *user = @"Gabriel"; int days = 3; NSString *s = [NSString stringWithFormat:@"posted by %@ (%d days ago)", user, days];
Swiftには、同じことを行うための文字列補間と呼ばれる機能がありますが、よりコンパクトで読みやすくなっています。
let user = "Gabriel" let days = 3 let s = "posted by \(user) \(days) ago"
次の式を使用することもできます。
let width = 2 let height = 3 let s = "Area for square with sides \(width) and \(height) is \(width*height)"
Swiftの文字列補間およびその他の新機能の詳細については、こちらをご覧ください。
関数
Swiftの関数定義はCとは異なります。関数定義の例を以下に示します。
func someFunction(s:String, i: Int) -> Bool { ... // code }
Swift関数はファーストクラスのタイプです。 これは、関数を変数に割り当てたり、それらをパラメーターとして他の関数に渡したり、タイプを返すようにしたりできることを意味します。
func stringLength(s:String) -> Int { return countElements(s) } func stringValue(s:String) -> Int { if let x = s.toInt() { return x } return 0 } func doSomething(f:String -> Int, s:String) -> Int { return f(s).successor() } let f1 = stringLength let f2 = stringValue doSomething(f1, "123") // 4 doSomething(f2, "123") // 124
ここでも、Swiftはf1
とf2
のタイプ( String
> Int
)を推測しますが、明示的に定義することもできます。
let f1:String -> Int = stringLength
関数は他の関数を返すこともできます。
func compareGreaterThan(a: Int, b: Int) -> Bool { return a > b } func compareLessThan(a: Int, b: Int) -> Bool { return a < b } func comparator(greaterThan:Bool) -> (Int, Int) -> Bool { if greaterThan { return compareGreaterThan } else { return compareLessThan } } let f = comparator(true) println(f(5, 9))
Swiftの関数のガイドはここにあります。
列挙型
Swiftの列挙型は、Objective-Cよりもはるかに強力です。 Swiftの構造体として、メソッドを持つことができ、値によって渡されます。
enum MobileDevice : String { case iPhone = "iPhone", Andro, WP8 = "Windows Phone8", BB = "BlackBerry" func name() -> String { return self.toRaw() } } let m = MobileDevice.Android print(m.name()) // "Android"
Objective-Cとは異なり、Swift列挙型は、整数に加えて、文字列、文字、または浮動小数点数を各メンバーの値として割り当てることができます。 便利toRaw()
メソッドは、各メンバーに割り当てられた値を返します。
列挙型もパラメーター化できます。
enum Location { case Address(street:String, city:String) case LatLon(lat:Float, lon:Float) func description() -> String { switch self { case let .Address(street, city): return street + ", " + city case let .LatLon(lat, lon): return "(\(lat), \(lon))" } } } let loc1 = Location.Address(street: "2070 Fell St", city: "San Francisco") let loc2 = Location.LatLon(lat: 23.117, lon: 45.899) print(loc1.description()) // "2070 Fell St, San Francisco" print(loc2.description()) // "(23.117, 45.988)"
列挙型の詳細については、こちらをご覧ください。

タプル
タプルは、複数の値を1つの複合値にグループ化します。 タプル内の値は任意のタイプにすることができ、互いに同じタイプである必要はありません。
let person = ("Gabriel", "Kirkpatrick") print(person.0) // Gabriel
個々のタプル要素に名前を付けることもできます。
let person = (first: "Gabriel", last: "Kirkpatrick") print(person.first)
タプルは、複数の値を返す必要がある関数の戻り型として非常に便利です。
func intDivision(a: Int, b: Int) -> (quotient: Int, remainder: Int) { return (a/b, a%b) } print(intDivision(11, 3)) // (3, 2) let result = intDivision(15, 4) print(result.remainder) // 3
Objective-Cとは異なり、Swiftはswitchステートメントでパターンマッチングをサポートしています。
let complex = (2.0, 1.1) // real and imaginary parts switch complex { case (0, 0): println("Number is zero") case (_, 0): println("Number is real") default: println("Number is imaginary") }
2番目のケースでは、数値の実数部は気にしないため、 _
を使用して何にでも一致させます。 いずれの場合も、追加の条件を確認することもできます。 そのためには、パターン値を定数にバインドする必要があります。
let complex = (2.0, 1.1) switch complex { case (0, 0): println("Number is zero") case (let a, 0) where a > 0: println("Number is real and positive") case (let a, 0) where a < 0: println("Number is real and negative") case (0, let b) where b != 0: println("Number has only imaginary part") case let (a, b): println("Number is imaginary with distance \(a*a + b*b)") }
比較またはcaseステートメントで使用する値のみをバインドする必要があることに注意してください。
タプルの詳細については、こちらをご覧ください。
クラスと構造
Objective-Cとは異なり、Swiftでは、カスタムクラスと構造用に個別のインターフェイスファイルと実装ファイルを作成する必要はありません。 Swiftを学習すると、単一のファイルでクラスまたは構造を定義する方法を学習し、そのクラスまたは構造への外部インターフェイスが他のコードで自動的に使用できるようになります。
クラスの定義
クラス定義は非常に単純です。
class Bottle { var volume: Int = 1000 func description() -> String { return "This bottle has \(volume) ml" } } let b = Bottle() print(b.description())
ご覧のとおり、宣言と実装は同じファイルにあります。 Swiftはヘッダーファイルと実装ファイルを使用しなくなりました。 この例にラベルを追加しましょう。
class Bottle { var volume: Int = 1000 var label:String func description() -> String { return "This bottle of \(label) has \(volume) ml" } }
labelはオプションではない変数であり、Bottleがインスタンス化されたときに値を保持しないため、コンパイラは文句を言います。 初期化子を追加する必要があります。
class Bottle { var volume: Int = 1000 var label:String init(label:String) { self.label = label } func description() -> String { return "This bottle of \(label) has \(volume) ml" } }
または、初期化されないプロパティにOptional
型を使用することもできます。 次の例では、 volume
をOptional Integer
にしました。
class Bottle { var volume: Int? var label:String init(label:String) { self.label = label } func description() -> String { if self.volume != nil { return "This bottle of \(label) has \(volume!) ml" } else { return "A bootle of \(label)" } } }
構造
Swift言語にもstructs
がありますが、Objective-Cよりもはるかに柔軟性があります。 次のコードチュートリアルでは、 struct
を定義しています。
struct Seat { var row: Int var letter:String init (row: Int, letter:String) { self.row = row self.letter = letter } func description() -> String { return "\(row)-\(letter)" } }
Swiftのクラスと同様に、構造体はメソッド、プロパティ、初期化子を持ち、プロトコルに準拠することができます。 クラスと構造体の主な違いは、クラスは参照によって渡されるのに対し、構造体は値によって渡されることです。
この例は、参照によるクラスの受け渡しを示しています。
let b = Bottle() print(b.description()) // "b" bottle has 1000 ml var b2 = b b.volume = 750 print(b2.description()) // "b" and "b2" bottles have 750 ml
struct
で同様のケースを試してみると、変数が値で渡されることがわかります。
var s1 = Seat(row: 14, letter:"A") var s2 = s1 s1.letter = "B" print(s1.description()) // 14-B print(s2.description()) // 14-A
いつstruct
を使用し、いつclass
を使用する必要がありますか? Objective-CおよびCの場合と同様に、いくつかの値をグループ化する必要がある場合は構造体を使用し、それらが参照されるのではなくコピーされることを期待します。 たとえば、複素数、2Dまたは3Dポイント、またはRGBカラー。
クラスのインスタンスは、伝統的にオブジェクトとして知られています。 ただし、Swiftのクラスと構造は、他の言語よりも機能がはるかに近く、クラスまたは構造タイプのインスタンスに多くの機能を適用できます。 このため、Swiftリファレンスで使用されるより一般的な用語はinstance
であり、これら2つのいずれにも適用されます。
ここでSwiftのクラスと構造の基本を学びます。
プロパティ
前に見たように、Swiftのプロパティは、クラスまたは構造体の定義内でvar
キーワードを使用して宣言されます。 let
ステートメントで定数を宣言することもできます。
struct FixedPointNumber { var digits: Int let decimals: Int } var n = FixedPointNumber(digits: 12345, decimals: 2) n.digits = 4567 // ok n.decimals = 3 // error, decimals is a constant
また、 weak
キーワードをプレフィックスとして付けない限り、クラスプロパティは強く参照されることに注意してください。 ただし、オプションではないプロパティが弱い場合は微妙な点があるため、AppleのSwiftガイドの自動参照カウントの章をお読みください。
計算されたプロパティ
計算されたプロパティは実際には値を格納しません。 代わりに、他のプロパティと値を間接的に取得および設定するためのゲッターとオプションのセッターを提供します。
次のコードは、計算された値のsign
のサンプルを提供します。
enum Sign { case Positive case Negative } struct SomeNumber { var number:Int var sign:Sign { get { if number < 0 { return Sign.Negative } else { return Sign.Positive } } set (newSign) { if (newSign == Sign.Negative) { self.number = -abs(self.number) } else { self.number = abs(self.number) } } } }
ゲッターを実装するだけで、読み取り専用プロパティを定義することもできます。
struct SomeNumber { var number:Int var isEven:Bool { get { return number % 2 == 0 } } }
Objective-Cでは、プロパティは通常、インスタンス変数によってサポートされ、明示的に宣言されるか、コンパイラによって自動的に作成されます。 一方、Swiftでは、プロパティに対応するインスタンス変数がありません。 つまり、プロパティのバッキングストアに直接アクセスすることはできません。 これがObjective-Cにあると仮定します
// .h @interface OnlyInitialString : NSObject @property(strong) NSString *string; @end // .m @implementation OnlyInitialString - (void)setString:(NSString *newString) { if (newString.length > 0) { _string = [newString substringToIndex:1]; } else { _string = @""; } } @end
Swiftでは、計算されたプロパティにはバッキングストアがないため、次のようなことを行う必要があります。
class OnlyInitialString { var initial:String = "" var string:String { set (newString) { if countElements(newString) > 0 { self.initial = newString.substringToIndex(advance(newString.startIndex, 1)) } else { self.initial = "" } } get { return self.initial } } }
プロパティについては、こちらで詳しく説明しています
つづく
ジェネリックス、Objective-Cライブラリとの相互作用、クロージャ、オプションの連鎖、演算子のオーバーロードなど、Swiftで学ぶべき重要な新しいことがたくさんあります。 単一のチュートリアルで新しい言語を完全に説明することはできませんが、Swiftプログラミングの学習についてさらに多くのことが書かれることは間違いありません。 ただし、このクイックリードは、時間を見つけてSwift言語の詳細を学ぶことができなかった多くの、Objective-C開発者が軌道に乗って、Swiftの鳥に新しい高みへと連れて行ってもらうのに役立つと思います。