iOS Safe Area 我所知道的全部

在 iOS 7 Apple 在 UIViewController 中引入了 topLayoutGuide 和 bottomLayoutGuide 属性来描述没有被覆盖(status bar, navigation bar, toolbar, tab bar, etc.)屏幕的区域。在 iOS 11 中,Apple 已经弃用了这些属性,并引入了 safe area。Apple 建议我们不要在 safe area 操作,在 iOS 11 中,当在 iOS App 中定位视图时,你必须使用新的 safe area API。 UIView 在 iOS 11 UIViewController topLayoutGuide 和 bottomLayoutGuide 属性已经被替换成了新的 UIView 中的 safe area: @available(iOS 11.0, *) open var safeAreaInsets: UIEdgeInsets { get } @available(iOS 11.0, *) open var safeAreaLayoutGuide: UILayoutGuide { get } safeAreaInsets 属性意味着屏幕可以覆盖从四个方向,而不仅仅是顶部和底部。当被 iPhone X 呈现时,我们就明白了为什么我们需要左右 insets。 iPhone 8 vs iPhone X safe area (portrait orientation) ...

March 29, 2018 · 5 min · 965 words · Me

UITableViewCell 自适应 UITextView 高度

使用 Auto Layout 让 UITableViewCell 自适应 UITextView 高度,效果演示: 99-projects-of-swift/029-tableviewcell-self-adaption 预备步骤 给 textView 上下左右建立相对于 cell 的约束 取消 textView 的 Scrolling Enabled 设置 tableView 估算高度 tableView.estimatedRowHeight = 70 设置 textView.delegate = self 关键点 如果在 textViewDidChange(textView:) 调用 tableView.reloadData() 会造成 textView 失去焦点,键盘隐藏。 解决方法: func textViewDidChange(textView: UITextView) { tableView.beginUpdates() tableView.endUpdates() } 这里带来了一个问题,当 textView 长度超过一屏或者过长时,在输入时 tableView 会跳动滚动 jumping and stuttering。 更好的解决方法: func textViewDidChange(textView: UITextView) { let currentOffset = tableView.contentOffset UIView.setAnimationsEnabled(false) tableView.beginUpdates() tableView.endUpdates() UIView.setAnimationsEnabled(true) tableView.setContentOffset(currentOffset, animated: false) } 禁用动画和重建表视图的内容偏移修正抖动。 ...

March 27, 2018 · 1 min · 87 words · Me

【译】iOS 单元测试和 UI 测试入门教程

iOS Unit Testing and UI Testing Tutorial 编写测试并不迷人 (glamorous),但是既然测试能让你闪闪发光 (sparkling) 的应用程序避免变成 (from turning into) 一堆乱七八糟的垃圾,那么说明测试是必要的。如果你正在阅读这篇教程,那么你已经知道你 应该 为代码和 UI 编写测试,但是你可能不知道如何做。 也许你已经有一个 “可以运行” 的应用,但想测试你正在进行的扩展应用的更改。也许你已经编写了一些测试,但不确定它们是否是 正确 的测试。或者,你已经开始开发一个新应用,想要边开发边测试。 这篇教程将告诉你如何: 使用 Xcode 的测试导航器来测试应用的模型和异步方法 通过使用存根 (stubs) 和模拟对象 (mocks) 模拟与库或系统对象的交互 测试 UI 和性能 使用代码覆盖率工具 在此过程中,你将学到一些测试高手常用的专业术语。 开始 首先,下载教程素材。它包含一个基于 UIKit Apprentice 中的示例应用的 BullsEye 项目。这是一个简单的运气和机会游戏。游戏逻辑在 BullsEyeGame 类中,你将在本教程中对其进行测试。 测试什么 在编写任何测试之前,重要的是了解基础知识。你需要测试什么? 如果你的目标是扩展现有应用,你应该首先为计划更改的任何组件编写测试。 一般来说,测试应该覆盖: 核心功能:模型类和方法及其与控制器的交互 最常见的 UI 工作流 边界条件 Bug 修复 测试的最佳实践 首字母缩写 FIRST 描述了有效单元测试的一套简明标准。这些标准是: Fast:测试应该快速运行。 Independent/Isolated:测试之间不应共享状态。 Repeatable:每次运行测试时,都应获得相同的结果。外部数据提供者或并发问题可能导致间歇性失败。 Self-validating:测试应完全自动化。输出应该是"通过"或"失败",而不是依赖程序员对日志文件的解释。 Timely:理想情况下,你应该在编写生产代码之前编写测试它们的测试。这被称为测试驱动开发。 遵循 FIRST 原则将使你的测试保持清晰有用,而不会成为应用开发的障碍。 ...

March 15, 2018 · 4 min · 680 words · Me

【Git 权威指南】读书笔记 - 协同模型

主要内容:【Git 协同模型】 经典 Git 协同模型 集中式协同模型 可以像集中式版本控制系统那样使用 Git,在一个大家都可以访问到的服务器上架设 Git 服务器,每个人从该服务器克隆代码,本地提交推送到服务器上。 金字塔式协同模型 虽然理论上每个开发者的版本库都是平等的,但是会有一个公认的权威的版本库,这个版本库由一个或者多个核心开发者负责维护(具有推送的权限)。 开源社区逐渐发展出金字塔模型,而这也是必然之选。 Topgit 协同模型 笔者注:Topgit 是否已经过时? 卖主分支 Vendor Branch 是在版本库中专门创建一个和上游同步的分支,一旦有上游代码发布就捡入到卖主分支中。 子模组协同模型 创建子模组 git submodule add /path/to/repos/libA.git lib/lib_a .gitmodules 的内容: cat .gitmodules [submodule "lib/lib_a"] path = lib/lib_a url = /path/to/repos/libA.git 克隆带子模组的版本库 git clone /path/to/repos/super.git /path/to/my/workspace/super-clone 子模组的版本库并不会默认克隆,如果需要克隆出子模组型式引用的外部库,需要执行: git submodule init git submodule update 在子模组中修改和子模组的更新 修改更新的方式和普通仓库一样。如果修改了子模块,要先推送子模块的修改,再推送主仓库,以防止其他人克隆 super 版本库、更新模组时因为找不到该子模组版本库相应的提交而导致出错。 查看子模组状态: git submodule status 子树合并 引入外部版本库 # 注册外部版本库 git remote add util /path/to/repos/util.git git fetch util # 查看所有分支 git branch -a # 从 util/master 远程分支创建一个本地分支 util-branch git checkout -b util-branch util/master 子目录方式合并外部版本库 # 在主分支,将分支 util-branch 读取到当前分支的一个子目录下 git read-tree --prefix=lib util-branch # 将 lib 目录下的文件更新出来 git checkout -- lib 现在还不能忙着提交,因为如果现在进行提交就体现不出来两个分支的合并关系。需要使用 Git 底层的命令进行数据提交。 ...

January 19, 2018 · 2 min · 339 words · Me

【Git 权威指南】读书笔记 - 和声

主要内容:【Git 协议与工作协同】、【冲突解决】、【Git 里程碑】、【Git 分支】、【远程版本库】、【补丁文件交互】 Git 协议与工作协同 Git 支持的协议 SSH、GIT、HTTP、HTTPS、FTP、FTPS、RSYNC 及前面已经看到的本地协议。 SSH 协议: ssh://[user@]example.com[:port]/path/to/repo.git/ [user@]example.com:path/to/repo.git/ GIT 协议,最常用的只读协议: git://example.com[:port]/path/to/repo.git/ HTTP[S] 协议: http[s]://example.com[:port]/path/to/repo.git/ 强制非快进式推送 git push -f 强制推送,会强制刷新服务器中的版本。 禁止非快进式推送 git --git-dir=/path/to/repos/shared.git config receive.denyNonFastForwards true 冲突解决 拉回操作中的合并 git pull = git fetch + git merge 合并策略 Merge Strategis Git 合并操作支持很多合并策略,默认会选择最适合的合并策略。例如,和一个分支进行合并时会选择 recursive 合并策略,当和两个或两个以上的其他分支进行合并时采用 octopus 合并策略。 git merge [-s <strategy>] [-X <strategy-option>] [<commit>...] This option forces conflicting hunks to be auto-resolved cleanly by favoring our version. git merge -s recursive -X ours [<commit>...] Merge branch obsolete into the current branch, using ours merge strategy: ...

January 17, 2018 · 3 min · 469 words · Me

R.swift 强类型引用资源文件

R.swift 获取强类型、自动编译的图片、字体、segues 等资源。 以避免无法编译时检查 字符串 的形式引用资源所导致的错误。 let icon = UIImage(named: "settings-icon") let font = UIFont(name: "San Francisco", size: 42) let color = UIColor(named: "indictator highlight") let viewController = CustomViewController(nibName: "CustomView", bundle: nil) let string = String(format: NSLocalizedString("welcome.withName", comment: ""), locale: NSLocale.current, "Arthur Dent") With R.swift let icon = R.image.settingsIcon() let font = R.font.sanFrancisco(size: 42) let color = R.color.indicatorHighlight() let viewController = CustomViewController(nib: R.nib.customView.name) let string = R.string.localizable.welcomeWithName("Arthur Dent") 配置 其中 GitHub 上有的就不再累述了,主要注意: 添加 R.generated.swift 不要勾选 Copy items if needed,软引用就好。 要在 .gitignore 添加 *.generated.swift 以避免不必要的冲突。 添加新的资源文件后需要 command + b 编译下,才可以使用。 .clr 颜色文件的创建和使用 使用 Xcode 创建 .clr 文件: 之后可以在其中添加颜色,选择颜色回车可以对颜色从新命名。 生成的 .clr 文件保存在 ~/library/Colors 下,可以导入到项目后再通过 R.color 使用。 Tips 打开、关闭隐藏文件: command + shift + . References XCode Tip: Color Palette

January 17, 2018 · 1 min · 116 words · Me

Xcode 不知名的实用技巧

状态栏 Help Search 框可以很方便的检索到相关的设置项。 Navigator ⌘ 1 .. ⌘ 7 可以切换窗口。 Show the Symbol navigator 在类不多时,可以方便看所有类的结构,类多时时使用下面的 filter 功能。 Show the Breakpoint navigator 点击右下角 + 选择 Exception Breakpoint..,可以在添加更明确的报错点,可以选择语言是 obj-c 还是 Swfit。 Utilities ⌘ ⌥ 1 .. ⌘ ⌥ 7 可以切换窗口。 Show the Code Snippet Library 代码片段模板,也可以将自己的写好的片段拖入。 Show the Media Library 可以直接从中拖拽图片成 UIImageView 放入 xib 中。 ...

January 12, 2018 · 1 min · 159 words · Me

回顾 2017

2017 关键词:Birds、离职、狼人杀、白洋淀、iOS、自如。 Birds Birds 是自己编写时间最长的一个 Web 项目。项目接手、改版、重构、迭代、盈利,上半年每天工作都是面对它。 Birds 良好的表现与需求互相推动,这点很重要,假如有需求而项目没有成长,或项目成长没了需求,对工程来说都只能是纸上谈兵、无事可做。项目中的规范的重要性,无论是代码还是数据库,只要项目不是夭折终将显现,对于规范性我绝不会开倒车,做任何妥协,种种经历只说明:这里欠的东西总会还。如何应对需求的千变万化,小结几点:模块化、组件化思想,功能多可配置,功能可拔插,功能方法粒度要小;不要对程序肆意进行打补丁式的修改,减少对流程入侵;当某一处的逻辑增加时要及时重新修改、定义流程;对需求目的的正确理解更是能高效开发。 对前端重新认识的一年。现在的前端和大学时刚刚接触时,已经大不一样了。前端能做的事情越来越多,很多业务逻辑都在前端处理,服务端只需要提供接口,分工合作更容易。浅尝 React Vue Webpack 后,也许前端才是自己的归宿。 离职 离职的不是我。老人走,新人来,新人走。离职一词在我身边跟了一年都没有停下来。同事离职的原因很多,离开北京、公司发展、自我发展… 马云说离职的原因就两个:1. 钱没给够。2. 受了委屈。我起初是认同这一说法的,但是后来觉得 “人” 或者说 “人的思想” 或者说 “人性” 在其中影响作用非常的大。相同的事情不同的角度看,结果相去甚远,如果基本的理念不同,那事情基本是无法调和的。 对做的事情的认同感,对自我的定位与认识,对现实情况的冷静思考,这几点需要反复咀嚼。 分享一篇文章:公司没大牛带,需要离职么?。对于刚入门的我们,这是一个很有代表性的问题。太多时候我们期待别人,忘了自己。公司有大牛,能跟着学是幸运,没有是常态。先接受了这个设定,会更容易找提高自己的方法。有没有大牛并不重要,我们是为了那个更好的自己。 狼人杀 2017 火的游戏很多:狼人杀、守望先锋、王者荣耀、吃鸡。狼人杀这一杀,好像杀到了毕业前和同学舍友在一起臭 high 的日子。可说骚话、互相 diss、互相吹捧,真真假假其乐无穷。最赤鸡的是鱼炸出了个女盆友,各路同学亲上加亲,无法克说。 白洋淀 我想 你说 你不要在孤单 让我做你的伴 白洋淀去过四次,那里的温泉过去两次,年中 Team Building 再喜加一,而这一次让这里有了美丽故事。喷泉、沙发,出现了对的人。 iOS React Native 的一波尝试后,走上了移动开发的道。Swift 让上 iOS 车的门槛降低不少,Swift API 趋向稳定,可以说这是最好的时候。GitHub 应该是再也放不下了,外文的书籍、文档确实靠谱啊,推荐一个教程网站 iOS Tutorials - Ray Wenderlich 真的零基础入门。 我相信:一个人语言的界限,就是他世界的边界。 自如 一场大火让无数人无家可归,年末换房也受牵连。被自如圈粉,其他中介的房子真的太 low 了。自如订房子居然也要抢,一波三折、失而复得。在没抢到房子时,真的想走,想离开这里了,很凄凉。最终是在公司对面住下了,过上了在家吃中饭晚饭的日子。 2018 Happy New Year 2017 自己是幸运的,2018 猥琐发育,不要浪,胜利属于伏地魔。 ...

December 31, 2017 · 1 min · 73 words · Me

【Git 权威指南】读书笔记 - 独奏 - Part 4

主要内容:【历史穿梭】、【改变历史】、【Git 克隆】 历史穿梭 查看条件个数: git rev-list HEAD | wc -l 版本表示法:git rev-parse git rev-parse pick out and massage parameters for other git commands. --git-dir 可以显示 Git 版本库的位置 --show-cdup 当前工作区目录的深度 --parseopt 可以用于被 Git 无关应用用于解析命令行参数 # 显示分支,tag git rev-parse --symbolic --branches git rev-parse --symbolic --branches # 显示定义的所有引用 git rev-parse --symbolic --glob=refs/* # 显示多个表达式的 SHA1 哈希值: git rev-parse master refs/heads/master 6652a0dce6a5067732c00ef0a220810a7230655e 6652a0dce6a5067732c00ef0a220810a7230655e ^后面的数字代表该提交的第几个父提交,~<n>就相当于连续<n>个符号^ git rev-parse A~3 A^^^ e80aa7481beda65ae00e35afc4bc4b171f9b0ebf e80aa7481beda65ae00e35afc4bc4b171f9b0ebf # 暂存区里的文件和HEAD中的文件相同 git rev-parse :gitg.png HEAD:gitg.png fc58966ccc1e5af24c2c9746196550241bc01c50 fc58966ccc1e5af24c2c9746196550241bc01c50 # 在提交日志中查找字串的方式显示提交 git rev-parse :/"Commit A" 81993234fc12a325d303eccea20f6fd629412712 版本范围表示法:git rev-list git rev-list 可以帮助研究 Git 的各种版本范围语法。 ...

December 25, 2017 · 3 min · 586 words · Me

iOS 招聘总结

自己也做了一次面试官。简历看到了很多,内容总结如下: 一些感受 一些基本的技能感觉不用写,不会吸引什么注意力。所以要精懂一些特别的技能,技术点。 一些 “与产品沟通” “安排工作”,我觉的也不用写,也没什么吸引力。 简历要体出自己擅长的地方,特别的地方,其他的一笔带过就可以。 简历上的字词的细节我比较在意,iOS & IOS,Xcode & XCode。 有 GitHub Blog 绝对的好评,但要有内容。 基础知识、业务能力、性格、气场。 技能 基础 Objective-C Swift 内存管理机制,MRC & ARC 代理、通知、Block 回调机制 闭包 KVC,KVO 机制 CoreData FMBD 归档存储 SQLite NSUserDefaults runtime 运行机制,runloop 运行机制 GCD NSOperation NSThread 多线程编程 Socket 通信 单例 观察者 MVVM RESTful 业务 瀑布流 抽屉 断点续传 媒体流 瀑布流 SSO 单点登陆 Framework Cocoapods 支付宝 高德 二维码扫描 友盟 极光推送 短信验证 微信 微博登陆 支付 in-app purchase SDWebImage AFNetworking Alamofire SnapKit MBProgressHUD IM 环信 Spring 动画 ICSDrawer 侧滑菜单 AVOS Cloud SDK ZXing ZBar 二维码 XMPP 其他 Axure 良好英文文档阅读能力 职责 模块封装 上架 迭代 沟通 整体框架 KVO 监听实现自定义下拉刷新 针对不同的网络状态 设置不同的缓存策略 各种 SDK 集成 HTML5 Native 相互调用 奇巧淫技 自己对 iOS 的理解还并不深,如何面试更有经验的人? ...

November 25, 2017 · 1 min · 118 words · Me