iOS 开发的官方 IDE 是 Xcode,它也是 Apple 平台最主流的开发工具。目前 Xcode 已经更新到第 9 个版本,功能也是涵盖开发、测试、性能分析、文档查询、源代码管理等多个方面,可谓是 App 开发一站式的平台。
Xcode 诞生于 2003 年,发展至今,已经可以支持除 Objective-C 和 Swift 之外其他 6 种语言:C、C++与 Objective-C 密不可分;自动化方面则多用 Ruby,例如我们熟知的 fastlane 和 cocoapods;Automation 工具的脚本大多采用 Javascript; 刚刚发布的 CoreML 采用的模型工具则是用 Python 编成。最新的 Xcode 采用完全由 Swift 重写的 Souce Editor,在代码修改、补全、模拟器运行方面有了很大提升。目前最大的缺点是稳定性不够。
对于 iOS 工程师而言,熟练运用 Xcode 是必备技能 ,而对 Xcode 的理解深浅亦是工程师水平的分水岭。本节将从基本的 Xcode 开发知识开始,逐渐深入到 Intruments 性能分析和 LLDB 调试,针对 Swift 专门设计的 Playground 也将有所涉及。
关键词:#调试 #命令
关键词:#调试 #编译器
class SampleViewController: UIViewController {
override func viewDidLoad() {
let numList: [Int]
let otherNumList = numList
let anotherNumList: [Int]?
}
}
这段代码中有三个错误。首先 numList 未初始化就赋值给 otherNumList ;其次 anotherNumList 并未使用;最后是 API 使用错误,没有调用 super.viewDidLoad() 方法。
var balance = 0
let fullTimeSalary = 1000, partTimeSalary = 1000
DispatchQueue.global().async {
for _ in 1...12 {
balance += partTimeSalary
}
}
for _ in 1...12 {
balance += fullTimeSalary
}
这段代码中两个线程同时对 balance 进行写操作,谁先写、balance 值为多少就会变成一个两个线程角力的情况。这种多线程对同一个值进行写操作的行为就是数据竞争。
如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群931542608来获取一份详细的大厂面试资料为你的跳槽多添一份保障。
UI 布局问题就是诸如尺寸设定没给全或者设定模糊,autolayout 引擎无法渲染的问题。内存问题最常见的就是内存泄漏,比如循环引用就是一个经典的错误。
关键词:#调试 #启动优化
App 启动时间过长,可能有多个原因造成。理论上 App 的启动时间是由 main() 函数之前的加载时间(t1)和 main() 函数之后的加载时间(t2)。
关于 t1 我们需要分析 App 的启动日志,具体方法是在 Xcode 中添加 DYLD_PRINT_STATISTICS
环境变量,并将其值设置为 1,这样就可以得到如下的启动日志:
Total pre-main time: 1.3 seconds (100.0%)
dylib loading time: 107.45 milliseconds (8.0%)
rebase/binding time: 376.56 milliseconds (28.2%)
ObjC setup time: 166.96 milliseconds (12.5%)
initializer time: 684.01 milliseconds (51.2%)
slowest intializers :
libSystem.dylib : 297.56 milliseconds (22.2%)
libMainThreadChecker.dylib : 33.00 milliseconds (2.4%)
libLLVMContainer.dylib : 113.09 milliseconds (8.4%)
ModelIO : 189.45 milliseconds (14.1%)
如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群931542608来获取一份详细的大厂面试资料为你的跳槽多添一份保障。
然后我们就可以知道,App 启动主要在这三个方面耗费时间,动态库加载,重定位和绑定,以及对象的初始化。所以优化的手段也有了,简单来说就是:
关于 t2,主要是构建第一个界面并完成渲染的时间。所以这个需要在具体的界面布局和渲染代码中进行打点观察,诸如 viewDidLoad 和 viewWillAppear 这两个函数就很值得关注。
关键词:#调试 #内存检测
有两种方法可以检测。
其一是使用 Xcode 中的 Memory Debug Graph。点击下图所示的调试工具栏中的按钮,Xcode 会自动检测内存相关的 memory runtime issue。点击相关问题处 Xcode 就会给出详细的循环引用示意图。
另一种解决方法是用 Instruments 里面的 Leak 选项——这是一个专门检测内存泄漏的工具。进入页面后发现 Leak Checks 中出现内存泄漏时,我们可以将导航栏切换到 call tree 模式下,强烈建议在 Display Settings 中勾选 Separate by Thread 和 Hide System Libraries 两个选项,这样可以隐藏掉系统和应用本身的调用路径,帮助我们更方便的找出 retain cycle 位置。
关键词:#调试
EXC_BAD_ACCESS 主要原因是访问了某些已经释放的对象,或者访问了它们已经释放的成员变量或方法。解决方法主要有以下几种:
关键词:#调试 #延时运行
let url = URL(string: “api.org/get”)
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
do {
let dictionary = try JSONSerialization.jsonObject(with: data!, options: [])
print(dictionary)
} catch {
print(“error!”)
}
}
答案是:什么内容都不会打印出来。原因是 Playground 执行完了所有语句,自动退出。如果要让 Playground 具备延时运行的特性,可以在 Playground 中加上一下代码:
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
这样我们就可以打印出返回的 dictionary 中的内容了。
如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群931542608来获取一份详细的大厂面试资料为你的跳槽多添一份保障。
关键词:#调试 #可视化开发
本题主要考察面试者的基本编程能力,对于 API 的熟悉程度和 Playground 可视化编程的了解。完整代码如下:
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
lazy var tableView: UITableView = {
return UITableView()
}()
lazy var nums: [Int] = {
var array = Array(0...99)
array.shuffle()
return array
}()
struct Constants {
static let CellIndentifier = "defaultCell"
}
override func viewDidLoad() {
super.viewDidLoad()
// autolayout for tableView
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let tableViewContraints = [
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.widthAnchor.constraint(equalTo: view.widthAnchor),
tableView.heightAnchor.constraint(equalTo: view.heightAnchor)
]
NSLayoutConstraint.activate(tableViewContraints)
// set up tableView
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: Constants.CellIndentifier)
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return nums.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Constants.CellIndentifier, for: indexPath)
cell.textLabel?.text = String(nums[indexPath.row])
return cell
}
}
PlaygroundPage.current.liveView = ViewController()
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。