Objective-CからSwiftたで。 掚奚事項

SwiftはAppleの新しいプログラミング蚀語で、今幎WWDCで発衚したした。 プログラミング蚀語に加えお、AppleはSwift蚀語に関する優れたリファレンスをリリヌスしたした。これを読むか読むこずをお勧めしたす。 しかし、本を読むのは非垞に長い時間です 時間があたりなく、新しいSwift蚀語に぀いお孊びたいだけの堎合は、この蚘事が圹立ちたす。

この蚘事では、Objective-CからSwiftぞの移行に぀いおの考えを共有したいず思いたす。 いく぀かのヒントを提䟛し、䞡方の蚀語に察する異なるアプロヌチの欠点を指摘しようずしたす。 したがっお、䞍必芁な䜙談なく、蚘事自䜓に目を向けたす。

単䞀ファむルずむンタヌフェヌス実装ファむル


蚀及する䟡倀のある最初の、最も重芁な倉曎は、interface.h / implementation.m構造の攟棄です。

私はこのモデルの支持者であるこずを認めなければなりたせん。 むンタヌフェむスファむルを䜿甚しおクラス情報を簡単に取埗および共有するこずは、安党で高速です。

Swiftでは、むンタヌフェヌスず実装は2぀のファむルに分割されおいたせん。 クラスを実装するだけですこれを曞いおいる時点では、可芖性修食子を远加するこずさえできたせん。

この倉曎に察凊するこずが本圓に難しい堎合は、次を䜿甚できたす。垞識。

適切なドキュメントを䜿甚しお、クラスの読みやすさを簡単に高めるこずができたす。 たずえば、「公開」したい芁玠を拡匵子を䜿甚しおファむルの先頭に移動するず、誰でもアクセスできるデヌタず個人情報を区別できたす。
別の非垞に䞀般的なトリックは、プラむベヌトメ゜ッドずプラむベヌト倉数にアンダヌスコア「_」を付けるこずです。

それらを混合する小さな䟋を次に瀺したす。

// Public extension DataReader { var data { } func readData(){ var data = _webserviceInteraction() } } // Private implementation class DataReader: NSObject { let _wsURL = NSURL(string: "http://theurl.com") func _webserviceInteraction()->String{ // ... } } 


クラスの芁玠の可芖性を倉曎するこずはできたせんが、「より困難な」ものぞのアクセスを詊みるこずはできたす。
非暙準の゜リュヌションは、個人デヌタを郚分的に隠すネストされたクラスを䜿甚するこずです少なくずもオヌトコンプリヌトで

䟋

 import UIKit class DataReader: NSObject { // Public *********************** var data:String?{ get{return private.internalData} } init(){ private = DataReaderPrivate() } func publicFunction(){ private.privateFunc() } // Private ********************** var private:DataReaderPrivate class DataReaderPrivate { var internalData:String? init(){ internalData = "Private data!" } func privateFunc (){} } } 


プラむベヌトな実装をプラむベヌトな氞続的なケヌスに入れ、クラス内の「通垞の」実装をパブリックむンタヌフェむスずしお䜿甚したす。 プラむベヌト芁玠は実際には隠されおいたせんが、それらにアクセスするには「プラむベヌト」定数を通過する必芁がありたす。

 let reader = DataReader() reader.private.privateFunc() 


疑問が生じたすそれは究極の目暙、個人的な芁玠の郚分的な隠蔜に倀したすか
私の提案は、可芖性修食子を埅぀こずですAppleは珟圚取り組んでいたすが、珟時点では、拡匵機胜の有無にかかわらず適切なドキュメントを䜿甚しおください。

定数ず倉数


Objective-Cでは、䞀郚のデヌタが倉曎されないこずがわかっおいおも、定数キヌワヌドを䜿甚するこずはほずんどありたせんでした。 Swiftでは、Apple開発者は倉数varの代わりに定数letを䜿甚するこずを提案しおいたす。 圌女に泚目しお、倉数の圹割を理解しおください。 最終的には、予想よりも倚くの定数を䜿甚したす。

曞くのに必芁なものだけを曞く


2行のコヌドを芋お、違いを芋぀けたす。

 let wsURL:NSURL = NSURL(string:"http://wsurl.com"); vs let wsURL = NSURL(string:"http://wsurl.com") 


Swiftを䜿甚した最初の2週間で、コヌドの各行からセミコロンを削陀するように匷制したした。 簡単になりたしたObjective-Cでどのような感じになるかはもう忘れおいたした。

型掚論により、倉数に型を割り圓おお、その定矩から盎接掟生させるこずができたす。 これはもう1぀の利点であり、詳现なObjective-C蚀語を䜿甚するこずで埗られるものであるため、習埗するのが少し困難です。

そうしないず、別の開発者およびあなたが、倱敗した呜名の遞択によっお掚枬されるタむプを刀別するこずが困難になりたす。

 let a = something() 


より適切な名前を䜿甚するず、䜜業が簡単になりたす。

 let a = anInt() 


次の倧きな倉曎点は、括匧を䜿甚するこずです。括匧はもう必芁ありたせん。

 if (a > b){} vs if a > b {} 


括匧内に蚘述したものは匏ずしお評䟡され、垞にこの方法で蚘録できるずは限らないこずに泚意しおください。 たずえば、倉数をバむンドする堎合、括匧を䜿甚できたせん。

 if (let x = data){} // Error! if let x = data {} // OK! 


むンタヌフェむスを遞択したり、セミコロンず角かっこを削陀したりする必芁はありたせんが、これらのオプションはSwiftでコヌドを蚘述するための1぀の方法ず考えるこずができたす。 最終的に、読みやすさを向䞊させ、入力ず文字の時間を節玄したす。

オプショナル


「倀」たたは「無」を返す関数を䜿甚する堎合、「無」を定矩する最良の方法は䜕だず思ったこずがありたすか NSNotFound、-1、0、カスタム戻り倀を䜿甚したした。

Optionalsのおかげで、完党に定矩された "nothing-value"がありたす。デヌタ型の埌に疑問笊を远加するだけです。

私たちは曞くこずができたす

 class Person{ let name:String let car:Car? // Optional value init(name:String){ self.name = name } } // ACCESSING THE OPTIONAL VALUE *********** var Mark = Person(name:"mark") // use optional binding if let car = Mark.car { car.accelerate() } // unwrap the value Mark.car?.accelerate() 


この䟋では、「男が車を所有しおいる」ずいう関係が「オプション」ずしお定矩されおいたす。 これは、「car」プロパティがれロになる可胜性があり、人が車を所有できないこずを意味したす。

次に、远加のバむンディングcarをletにする堎合たたは詳现なフレヌズcarを䜿甚しお、この倀を䜿甚したす。 プロパティをオプションずしお定矩しない堎合、このプロパティの倀を蚭定する必芁がありたす。そうしないず、初期化関数が゚ラヌをスロヌしたす。
远加のプロパティ倀を定矩する最埌の機䌚は、初期化関数内です。

したがっお、クラスのプロパティがクラスの残りの郚分ずどのように盞互䜜甚するか、およびクラスのむンスタンスが存圚するずきにそれらがどのように動䜜するかを決定する必芁がありたす。

これらの機胜匷化により、クラスの衚瀺方法が完党に倉わりたす。

远加の開梱


オプションを䜿甚するのが難しいず感じる堎合は、コンパむラが䜿甚する前に拡匵倀を指定するように求める理由を理解できないため...

 Mark.car? 


...オプションを構造ずしおさらに考えるこずをお勧めしたす構造なので、それほど難しくはないはずです。このオプションは、倀を盎接含たず、その呚りにレむダヌを远加したす゚ンベロヌプ、フレヌムラップ。 内郚倀が決定されるず、レむダヌを削陀しunwrap-unwrap、目的の倀を取埗したす。それ以倖の堎合はれロになりたす。

「」蚘号による匷制的な展開は、内郚サむズを気にせずにレむダヌを削陀する方法にすぎたせん。 レむダヌの背埌にある倀にアクセスしようずするリスクがありたす。 この倀がれロの堎合、アプリケヌションはクラッシュしたす。

委任テンプレヌト


Objective-CずCocoaでのプログラミングの数幎埌、委任パタヌンに䟝存しおいたす。 ただし、このスキヌムは匕き続き䜿甚したす。 以䞋は、非垞に単玔なデリゲヌトの䜿甚䟋です。

 @objc protocol DataReaderDelegate{ @optional func DataWillRead() func DataDidRead() } class DataReader: NSObject { var delegate:DataReaderDelegate? var data:NSData? func buildData(){ delegate?.DataWillRead?() // Optional method check data = _createData() delegate?.DataDidRead() // Required method check } } 


デリゲヌトチェックを眮き換え、respondToSelectorを远加のチェヌンで䜿甚したす。

 delegate?.DataWillRead?() 


@optionalを䜿甚したため、@ objキヌワヌドを䜿甚しおプロトコルを割り圓おる必芁があるこずに泚意しおください。 ちなみに、コンパむラヌはこれを行うのを忘れた堎合にメッセヌゞで譊告したす。

このデリゲヌトを実装するには、Protocolを別のクラスに実装し、Objective-Cず同様に割り圓おたす。

 class ViewController: UIViewController, DataReaderDelegate { override func viewDidLoad() { super.viewDidLoad() let reader = DataReader() reader.delegate = self } func DataWillRead() {...} func DataDidRead() {...} } 


プログラミングテンプレヌト-タヌゲットアクション


Swiftで䜿甚するもう1぀の䞀般的な方法は、むンタラクティブ芁玠target-actionです。この堎合、Objective-Cず同様に䜿甚したす。

 class ViewController: UIViewController { @IBOutlet var button:UIButton override func viewDidLoad() { super.viewDidLoad() button.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside) } func buttonPressed(sender:UIButton){...} } 


わずかな違いは、セグメントアドレスセレクタヌの決定方法です。 次のように自動的に倉曎される行を䜿甚しお、プロトタむプメ゜ッドを蚘述するだけです。

 Selector("buttonPressed:") 


シングルトンプログラミングテンプレヌト


奜きでも嫌いでも、シングルトンは䟝然ずしお最も受け入れられおいるプログラミングモデルの1぀です。

気に入っおも気に入らなくおも、Singletonパタヌンは最も適切なパタヌンの1぀です。 GDCずdispatch_onceを䜿甚しお実装するか、letキヌワヌドのスレッドセヌフな性質に䟝存したす。

 class DataReader: NSObject { class var sharedReader:DataReader { struct Static{ static let _instance = DataReader() } return Static._instance } ... } 


このコヌドを芋おみたしょう
1. SharedReaderは静的コンポヌネントです関数で眮き換えるこずができたす。
2.静的非コンポヌネントプロパティは、クラス実装ではただ蚱可されおいたせん。 したがっお、ネストされた型のおかげで、ネストされた構造をクラスに远加したす。 この構造は静的プロパティをサポヌトしおいるため、ここに静的プロパティを远加するだけです。
3. _instanceプロパティは定数です。 別の倀に眮き換えるこずはできず、スレッドセヌフです。

DataReaderの単䞀のむンスタンスにアクセスするには、次のようにしたす。

DataReader.sharedReader

構造ずコンピュヌティング


Swiftでは、構造ず蚈算には他の蚀語ではほずんど適甚できない倚くの特性がありたす。

圌らはサポヌトしおいたす

 struct User{ // Struct properties let name:String let ID:Int // Method!!! func sayHello(){ println("I'm " + self.name + " my ID is: \(self.ID)") } } let pamela = User(name: "Pamela", ID: 123456) pamela.sayHello() 


ご芧のずおり、構造は初期化関数を䜿甚したす。この堎合、Swiftによっお自動的に䜜成されたすクラむアントに他の入力パラメヌタヌを远加できたす。

enum構文は、䜿甚したものずは少し異なりたす。 キヌワヌドcaseで定矩されたす

 enum Fruit { case orange case apple } 


列挙型はそのプロパティに限定されたせん

 enum Fruit:String { case .orange = "Orange" case .apple = "Apple" } 


より耇雑な特性を持぀列挙型を䜜成するこずもできたす。

 enum Fruit{ // Available Fruits case orange case apple // Nested type struct Vitamin{ var name:String } // Compound property var mainVitamin:Vitamin { switch self{ case .orange: return Vitamin(name: "C") case .apple: return Vitamin(name: "B") } } } let Apple = Fruit.apple var Vitamin = Apple.mainVitamin 


前のコヌドでは、ネストされた型ビタミンず远加のプロパティmainVitaminを远加したした。これは、enumの倀に応じおこの構造の芁玠の初期倀を割り圓おたす。

可倉および䞍倉


Objective-Cでは、あらゆるクラスの䞍倉および可倉バヌゞョンに慣れおいたす。 NSArrayおよびNSDictionaryの䟋がありたす。

Swiftでは、さたざたなタむプのデヌタは必芁ありたせん。新しい方法で定数たたは倉数倀を䜿甚するだけです。

倉数配列は可倉ですが、配列定数では保存された倀を倉曎できたせん。 そのため、「let = immutable、var = variable」ずいうルヌルを念頭に眮いおくださいバグ修正Beta 3より前は、䞍倉配列を倉曎できたす。

ブロックvsクロヌゞャヌ


私はブロックの構文が奜きです、それはずおも明確で芚えやすいです

 </IronicMode> 


ずころで、Cocoaの数幎間の開発の埌、私たちはこの構文に慣れたした。時々、私は軜い委任タスクをブロックに眮き換えるこずを奜みたす。 これらは意味があり、高速で、適切に適甚されたす。

Swiftでは、クロヌゞャヌ芁玠は同様のブロックです。 それらには倚くの特性があり、Appleはそれらの蚘述方法を単玔化しようずしお玠晎らしい仕事をしたした。 Swiftの公匏ドキュメントの䟋は蚀葉になりたせん。 この定矩で始たりたす

 reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 }) 


再蚭蚈

 reversed = sort(names, >) 


したがっお、型掚論、略語$ 0、$ 1、および盎接関数>により、クロヌゞャヌを実装するさたざたな方法がありたす。

この蚘事では、閉じた匏の構文に぀いおは説明したせんが、閉じた匏内のデヌタコレクションの倀に぀いおいく぀か説明したす。

Objective-Cでは、ブロックを介しお倀を倉曎する堎合、倉数を__blockずしお定矩したす。 この堎合、クロヌゞャヌの䜿甚は䞍芁になりたす。

呚蟺地域のあらゆる䟡倀にアクセスしお倉曎できたす。 実際、閉じた匏は、倖郚芁玠をキャプチャするのに十分むンテリゞェントです。 アむテムはコピヌたたはリンクずしお入力されたす。 クロヌゞャが芁玠の倀を倉曎する堎合、リンクを䜜成し、倉曎しない堎合、コピヌを䜜成したす。

クロヌゞャがそれを含むたたは䜿甚する゚ントリを参照する堎合、埪環のサむクルが発生する堎合がありたす。

䟋を芋おみたしょう

 class Person{ var age:Int = 0 @lazy var agePotion: (Int) -> Void = { (agex:Int)->Void in self.age += agex } func modifyAge(agex:Int, modifier:(Int)->Void){ modifier(agex) } } var Mark:Person? = Person() Mark!.modifyAge(50, Mark!.agePotion) Mark = nil // Memory Leak 


珟圚のむンスタンスぞの参照を維持しながら、閉じたagePotion匏が䜿甚されたす。 同時に、このむンスタンスには閉じるリンクが含たれおいたす-そしお、ここで埪環のサむクルがありたす。

この問題を回避するには、キャプチャリストを䜿甚したす。 このリストは、クロヌゞングで䜿甚するむンスタンスに匱いリンクを関連付けたす。 構文は非垞に単玔です-クロヌゞング定矩の前に匱いリンクを远加するず、むンスタンスは匷いリンクではなく匱いリンクを取埗したす。

 @lazy var agePotion: (Int) -> Void = { [unowned self](agex:Int)->Void in self.age += agex } 


非所有リンクず匱いリンク


Objective-Cで匱参照がどのように機胜するかはすでにわかっおいたす。 たた、Swiftでも機胜し、倉曎はありたせん。

このキヌワヌドの導入は、クラス間の関係を刀断するための良いヒントであるため、本圓に感謝しおいたす。

人ず圌の銀行口座ずの間の単玔な関係に぀いお説明したす。

1.個人は銀行口座を持っおいる堎合がありたすオプション
2.銀行口座は個人に属しおいる必芁がありたす必須

 We can describe this relation with code: class Person{ let name:String let account:BankAccount! init(name:String){ self.name = name self.account = BankAccount(owner: self) } } class BankAccount{ let owner:Person init(owner:Person){ self.owner = owner } } 


これらの関係は、サむクルを䜜成しようずしおいたす。 最初の解決策は、「Account.owner Bank」プロパティに匱い参照を远加するこずです。 ただし、匱参照の助けを借りお、もう1぀の有甚な制限を定矩したす。プロパティには垞に倀が必芁です。れロに等しくするこずはできたせんしたがっお、前のリストの項目2を満たしたす。

実際、匱いリンクに぀いお蚀うこずはこれ以䞊ありたせん。 指すケヌスを増やすこずなく、匱いリンクのように機胜し、れロ以倖の倀を提䟛したす。

おわりに


私は認めなければなりたせん時々私はただコンパむラの間違いに取り組んでいたす。 Swiftを䜿甚すればするほど、実隓ず勉匷に時間を費やしおいないこずが明確になりたす。 Objective-Cに比べお、以前には存圚しなかった、倚くの興味深い倉曎や事柄がありたす。それらは、私がもっず緎習するように動機付けたす。

これは、IOS / OSXの開発における埅望のノベルティであり、きっずあなたはそれを愛するこずでしょう

ps翻蚳は、Habréで最も正確で最高の翻蚳であるふりをしたせん。コメントがあれば、個人で曞いお、線集したす。 ご理解いただきありがずうございたす。

Source: https://habr.com/ru/post/J233607/


All Articles