そのため、変数を宣言して戻り値を保持し、次の行でその変数を返すのが好きなので、コードのデバッグが簡単になります。戻り行にブレークポイントを設定して、それが返す値を確認するだけです。私はこれをどこでも使用しており、すべてのコードをデバッグしやすくしています。
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let cellCount = models.count
return cellCount
}
ただし、メソッドが理にかなっているために満たす必要があるオプションとさまざまな条件があるシナリオがあります。ガード ステートメントは、ピラミッド オブ ドゥームを導入せずに、いくつかの条件が満たされていることを確認するのに最適です。
しかし、アーリー リターンの問題は、メソッドから少なくとも 2 つの終了ポイントを取得することです (このコンテキストでguard
は a が必要なためreturn
)。これにより、デバッグが難しくなります。
// Instantiate using dependency injection
private let reachability: ReachabilityProtocol
private let apiClient: APIClientProtocol
// Returns true if could start login request, else false
func loginUser(username: String, password: String) -> Bool {
defer {
// Not possible, would be nice! Return value would be an implicitly declared variable
// exaclty like the variables 'newValue' and 'oldValue' in property observers!
print("return value: \(returnValue)")
}
guard reachability.isOnline && !username.isEmpty && !password.isEmpty { return false }
apiClient.loginUser(username, password: password)
return true
}
Swift 3.Xで defer ステートメントが戻り値をキャッチできるようになれば素晴らしいと思いませんか?
これにより、デバッグが非常に簡単になりますが、それでもguard
早期リターンを利用できます。私はコンパイラなどを書くことについてこれまで何の洞察も持っていませんが、Swift の今後のバージョンでこれを実装するのはそれほど難しくないと思いますか?
複数の出口点を持つメソッドの戻り値を読み取るための単一のポイントを達成する別の方法を思い付くことができますか? (私が提案した改善を待つ必要はありdefer
ませんか?)
編集:
上記のログインの例は完璧な例ではありません。申し訳ありませんが、なぜそのようなコードを書くのでしょうか? ハハ!しかし、他にも多くの同様のシナリオがあります。おそらく次のようなもので、使用do-try-catch
するとコードのデバッグが難しくなります。
// We don't know the return value of this function! Makes it hard to debug!
func fetchUserByFirstName(firstName: String, andLastName lastName: String, fromContext context: NSManagedObjectContext) -> User? {
defer {
// Not possible, would be nice! Return value would be an implicitly declared variable
// exaclty like the variables 'newValue' and 'oldValue' in property observers!
print("return value: \(returnValue)")
}
guard !firstName.isEmpty else { print("firstName can't be empty"); return nil }
guard !lastName.isEmpty else { print("lastName can't be empty"); return nil }
// Imagine we have some kind of debug user... Does not really make sense, but good for making a point.
guard firstName != "DEBUG" else { return User.debugUser }
let fetchRequest = NSFetchRequest(entityName: Users.entityName)
let predicate = NSPredicate(format: "firstName == \(firstName) AND lastName == \(lastName)")
fetchRequest.predicate = predicate
do {
let user = try context.executeFetchRequest(fetchRequest)
return user
} catch let error as NSError {
print("Error fetching user: \(error)")
}
return nil
}