错误表现:使用!强制解包一个值为nil的可选类型,导致程序崩溃。例如:
var name: String? = nil
print(name!) // 运行时崩溃:Unexpectedly found nil while unwrapping an Optional value
解决方法:
if let或guard let安全解包,仅在值存在时执行代码。if let safeName = name {
print(safeName) // 安全访问
} else {
print("Name is nil") // 处理nil情况
}
nil值提供默认值,避免解包操作。let unwrappedName = name ?? "Default Name" // 若name为nil,返回"Default Name"
nil时使用!(如IBOutlet在viewDidLoad中已连接)。错误表现:访问数组中不存在的索引,导致运行时崩溃。例如:
let numbers = [1, 2, 3]
print(numbers[3]) // 运行时崩溃:Index out of range
解决方法:
indices属性或count判断索引是否在合法范围。let index = 3
if numbers.indices.contains(index) {
print(numbers[index]) // 安全访问
} else {
print("Index \(index) is out of bounds") // 处理越界情况
}
first/last属性:若需访问首尾元素,优先使用first(返回Optional)或last,避免手动计算索引。错误表现:对不兼容的类型进行操作(如将String当作Int使用),导致编译错误或运行时崩溃。例如:
let animal: String = "Dog"
let number: Int = animal // 编译错误:Cannot convert value of type 'String' to specified type 'Int'
解决方法:
Int与String不能直接赋值)。as?(可选转换)或as(强制转换,需确保兼容)进行类型转换,并处理可能的失败。let stringNumber: String = "123"
if let number = Int(stringNumber) { // 可选转换,成功返回Int?,失败返回nil
print(number) // 输出:123
} else {
print("Type conversion failed") // 处理转换失败
}
let num = 10推断为Int)。错误表现:两个对象相互强引用(如类实例中的self闭包),导致内存泄漏(对象无法释放)。例如:
class TimerManager {
var closure: (() -> Void)?
func startTimer() {
closure = {
self.doSomething() // 强引用self,形成循环
}
}
func doSomething() {}
}
解决方法:
[weak self]或[unowned self]打破强引用。weak表示可选引用(可能为nil),unowned表示非可选引用(假设对象不会为nil)。class TimerManager {
var closure: (() -> Void)?
func startTimer() {
closure = { [weak self] in // 使用weak捕获self
self?.doSomething() // 安全访问
}
}
func doSomething() {}
}
self:若需长期持有对象,考虑使用unowned(需确保对象生命周期)。错误表现:未处理可能抛出错误的函数,导致程序崩溃。例如:
enum FileError: Error {
case fileNotFound
}
func readFile(at path: String) throws {
throw FileError.fileNotFound
}
readFile(at: "invalid/path") // 未处理错误,编译错误(需用try/catch)
解决方法:
do-catch捕获错误:对可能抛出错误的函数使用try,并通过catch处理错误。do {
try readFile(at: "invalid/path")
} catch FileError.fileNotFound {
print("File not found") // 处理特定错误
} catch {
print("Unknown error: \(error)") // 处理其他错误
}
Error协议),通过throw抛出错误,明确错误来源。enum LoginError: Error {
case invalidCredentials
}
func login(username: String, password: String) throws {
if username.isEmpty || password.isEmpty {
throw LoginError.invalidCredentials
}
}
throws:若函数可能抛出错误,需在声明中添加throws关键字,提醒调用者处理错误。错误表现:协议扩展提供的默认实现可能掩盖子类的特定逻辑,导致预期之外的行为。例如:
protocol Drawable {
func draw()
}
extension Drawable {
func draw() {
print("Default drawing")
}
}
class Circle: Drawable {
func draw() {
print("Drawing a circle")
}
}
let shapes: [Drawable] = [Circle(), Circle()]
shapes.forEach { $0.draw() } // 输出两次"Default drawing"(扩展的默认实现覆盖了子类的方法)
解决方法:
self调用子类方法,或在子类中重写扩展方法。protocol Drawable {
func draw()
}
extension Drawable {
func draw() {
self.draw() // 递归调用,强制子类实现
}
}
class Circle: Drawable {
func draw() {
print("Drawing a circle")
}
}
错误表现:误用类(引用类型)代替结构体(值类型),导致意外的数据共享。例如:
class Person {
var name: String
init(name: String) {
self.name = name
}
}
var person1 = Person(name: "Alice")
var person2 = person1
person2.name = "Bob"
print(person1.name) // 输出"Bob"(person1和person2共享同一对象)
解决方法:
struct Person {
var name: String
}
var person1 = Person(name: "Alice")
var person2 = person1
person2.name = "Bob"
print(person1.name) // 输出"Alice"(person1未被修改)
UIViewController)。错误表现:在后台线程更新UI,导致界面卡顿或崩溃(UI操作必须在主线程执行)。例如:
DispatchQueue.global().async {
let data = fetchData() // 后台线程获取数据
DispatchQueue.main.async {
self.label.text = data // 主线程更新UI
}
}
解决方法:
DispatchQueue切换线程:耗时操作(如网络请求、数据库查询)放在后台线程(DispatchQueue.global()),UI更新放在主线程(DispatchQueue.main)。DispatchQueue.global().async {
let data = fetchData()
DispatchQueue.main.async {
self.label.text = data
}
}
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。