gpt4 book ai didi

ios - Swift:通过能够在 defer 语句中捕获返回值来简化调试

转载 作者:搜寻专家 更新时间:2023-10-31 22:59:44 25 4
gpt4 key购买 nike

所以我喜欢声明变量来保存返回值,然后在下一行返回所述变量,这样可以很容易地调试我的代码,我可以在返回行设置一个断点,看看它返回什么值。我在任何地方都使用它,它使我的所有代码更容易调试。

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let cellCount = models.count
return cellCount
}

但是您会遇到这样一种情况,您必须满足可选项和不同的条件才能使您的方法有意义。 The guard statement非常适合确保满足某些条件,同时不引入 pyramids of doom .

但是早期返回的问题是你从你的方法中得到至少两个退出点(因为 guard 在这个上下文中需要一个 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 能做到 the defer statement 就太棒了能够捕获返回值,不是吗?

这将使调试变得更加容易,同时仍然使用 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
}

最佳答案

我喜欢你建议的 Swift 改进 defer捕获返回值。

这是可行的,但它并不完美,因为它需要一些额外的工作(和代码困惑),但您可以通过声明 returnValue 手动完成它与 let在你的函数的顶部,赋予它与函数返回相同的类型。然后,替换所有的 return <something>returnValue = <something>; return returnValue .

通过声明returnValuelet ,如果你忘记赋值 returnValue,Swift 会让你知道在离开功能之前。所以如果你添加一个新的 return给你的函数,你的函数不会编译,直到你分配 returnValue .您会看到错误:错误:在初始化之前使用了常量“returnValue”

func fetchUserByFirstName(firstName: String, andLastName lastName: String, fromContext context: NSManagedObjectContext) -> User? {
let returnValue: User?
defer {
print("return value: \(returnValue)")
}

guard !firstName.isEmpty else { print("firstName can't be empty"); returnValue = nil; return returnValue }
guard !lastName.isEmpty else { print("lastName can't be empty"); returnValue = nil; return returnValue }
// Imagine we have some kind of debug user... Does not really make sense, but good for making a point.
guard firstName != "DEBUG" else { returnValue = User.debugUser; return returnValue }
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)
returnValue = user; return returnValue
} catch let error as NSError {
print("Error fetching user: \(error)")
}
returnValue = nil; return returnValue
}

或者(只是在这里集思广益...),将具有多个导出点的函数放入内部函数中,然后调用它:

func fetchUserByFirstName(firstName: String, andLastName lastName: String, fromContext context: NSManagedObjectContext) -> User? {

func innerFunc(firstName: String, andLastName lastName: String, fromContext context: NSManagedObjectContext) -> User? {

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.first as? User
} catch let error as NSError {
print("Error fetching user: \(error)")
}
return nil
}

let returnValue = innerFunc(firstName, andLastName: lastName, fromContext: context)
print("return value: \(returnValue)")
return returnValue
}

关于ios - Swift:通过能够在 defer 语句中捕获返回值来简化调试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38394499/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com