Swift Examples - Inheritance
The Swift Programming Language Examples
源码在 GitHub:https://github.com/gewill/The-Swift-Programming-Language-2.1-Examples
Playground ->
1 | // : Playground - noun: a place where people can play |
The Swift Programming Language Examples
源码在 GitHub:https://github.com/gewill/The-Swift-Programming-Language-2.1-Examples
Playground ->
1 | // : Playground - noun: a place where people can play |
The Swift Programming Language Examples
源码在 GitHub:https://github.com/gewill/The-Swift-Programming-Language-2.1-Examples
写了一段时间的 Swift 后,又来恶补基础知识了。
Playground ->
1 | // : Playground - noun: a place where people can play |
使用代码自动布局,需求还是有的,虽然很习惯了 IB 来做。参看 Programming iOS 9。
一共三个方法:
感觉 anchor 一个折中的方案,语法比 constraints 简洁,符合 IB 设计和添加约束的思路。美中不足是仅支持 iOS 9。
The NSLayoutAnchor class is a factory class for creating NSLayoutConstraint objects using a fluent API. Use these constraints to programatically define your layout using Auto Layout.
具体的使用语法都很简单,贴一个书中的 Demo:
1 | let v1 = UIView(frame: CGRectMake(100, 111, 132, 194)) |
兼容 iOS 8 以下的,但是超级啰嗦。
1 |
|
这个语法支持 iOS 6,而且语法最为简洁直观。也是
Programming iOS 9 书中推荐的方案。实际项目尝试了上面两种两种方法后,想要更短的代码量的话,还是 Visual format notation 最为合适。这里也推荐大家,还很容易理解其语法,而且 console debugging 也会优先显示该语法。
1 | <NSLayoutConstraint:0x7f855ad1bb00 H:[UIButton:0x7f855ad1bba0'Button'(46@188)] priority:188> |
当然这些都是不用 IB 和 View Debugging / Reveal 情况下的选择。
还有个优点就是类 ASCII-art,可视化的样式描述。
The Visual Format Language lets you use ASCII-art like strings to define your constraints. This provides a visually descriptive representation of the constraints.
下面是一个 CustomToolBar 的 Demo:
1 | import UIKit |
经过几次项目的实践,发现还是 Visual Format 最好用,简洁直观。
在 Swift 大行其道,Objective-C 渐行渐远的今天,这本书看起来还是获益匪浅。按照52条方法目录摘录一些笔记。
Objective-C 为 C 语言添加了面向对象的特性,是其超集。Objective-C 使用动态绑定的消息结构,运行时才会检查对象的类型。接受一条消息后,究竟执行何种代码,由运行期环境而非编译器决定。
自动合成属性:@property
,指定实例变量名称:@synthesize
,属性特质:原子性/读写权限/读写方法名/内存管理,都做有详细的解释,就不在此赘述了。
直接访问实例变量:
例如:
1 | id returnValue = [someObject messageName: parameter]; |
someObject 叫做接受者(receiver),messageName 叫做选择子(selector),选择子和参数合起来称为消息(message)。编译器看到消息后将其转换为一条标准的 C 语言函数调用,所调用函数 objc_msgSend,原型如下:
1 | void objc_msgSend(id self, SEL cmd, ...) |
编译器会把消息转换为如下函数:
1 | id returnValue = objc_msgSend(someObject, |
objc_msgSend 函数会依据接受者与选择子的类型,来搜寻接受者所属的类中方法列表(list of methods ),找到就跳至实现代码。若找不到就沿着继承体系向上查找。最终找不到就执行消息转发(message forwarding)。
未完
几乎都是两个人的对话,从双方羞涩的看向对方,到因为一对德国夫妻吵架而对视。男主鼓起勇气就此打开话题,聊天聊地,就此很愉快的旅程开始了。不管现实生活和情感是否顺利,但是两人总有新的话题和趣闻。当 Jesse 邀请下车游玩时候故事才真正开始。
开始的找有趣的地方,到后来随意的逛街道,酒吧,看手相,看日落,餐厅里互打电话,晚上草地聊天,次日火车道别。两人不太想落入俗套的留电话地址的偶遇,固执的开始时声明不留电话。因此格外珍惜相遇的这一天,玩的尽兴,聊得深入心灵。酒吧里算是爱情观的吐槽:人总是寻求被爱的多一点。也都是害怕重新承受之前恋爱分手之痛。看手相部分引起了一些争执,Jesse 理性的戳穿手相师和填词诗人的把戏,Céline 的满足和感动都搅合了。餐厅里的打电话很有意思,感觉 Céline 的很多时候也是主动地吐露情愫。
最后火车送别明明很不舍,但双方还是很坚持之前的想法不把这次邂逅变成俗套的艳遇。不过最后也做了妥协,约定六个月后此地在相见,还因为从今天还是昨天算起而争执了一番。说明内心是多么的喜欢对方,却又害怕伤害的顾忌而妥协。
电影里面男女主角都是普通的人的性格特点和际遇,但因为相互吸引和聚到一起,一天虽短,但却异常有趣。或者这样的爱情很奢侈,但是或者这就是不讲婚姻时纯粹的爱情。
Auto Layout Guide: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/index.html#//apple_ref/doc/uid/TP40010853-CH7-SW1
参考文章 iOS开发 - 处理不等高TableViewCell的小花招,实践出真知,也是费了一番力气才把文章 Cell 使用 Auto Layout自动算高。眼高手低总是有的,所以以后不仅要学习开发的思路方法论,重要是在实践一遍。
Auto Layout设置好高度约束。不要实现- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
1 | (void)viewDidLoad { |
1 | - (TableViewCell *)tableView:(UITableView *)tableView |
源码:https://github.com/gewill/test-projects/tree/master/test%20auto%20height%20cell
Swift中的内存指针讲解的很清楚:http://onevcat.com/2015/01/swift-pointer/。
Apple期望在Swift中指针能够尽量减少登场几率,因此在Swift中指针被映射为了一个泛型类型,并且还比较抽象。Swift中,指针都使用一个特殊的类型来表示,那就是UnsafePointer
还有苹果官方博客:Interacting with C Pointers。
下面代码是数组指针用法:
// Swift Memory UnsafePointer
var array = [1, 2, 3, 4, 5]
var arrayPtr = UnsafeMutableBufferPointer<Int>(start: &array, count: array.count)
// baseAddress 是第一个元素的指针
var basePtr = arrayPtr.baseAddress as UnsafeMutablePointer<Int>
print(basePtr.memory) // 1
basePtr.memory = 10
print(basePtr.memory) // 10
//下一个元素
var nextPtr = basePtr.successor()
print(nextPtr.memory) // 2
print(array) // [10, 2, 3, 4, 5]
源于微信群里一个问题讨论,具体陈铭嘉博客总结的很详细:http://www.jianshu.com/p/9a2952c792e6。
我主要是实践验证一下文章中的代码,其中Swift中的内存指针参看:http://onevcat.com/2015/01/swift-pointer/。
1 | //第一层理解: |
输出:
1 | 0x7fd2e2501ff0 and 0x7fd2e2501ff0 |
1 | //copy array swift |
输出:
1 | [1, 2, 3, 4, 5] |
原文地址:https://swift.org/documentation/api-design-guidelines.html
These are draft API guidelines being developed as part of the Swift 3.0 effort. 这些 API 指南草稿将作为 Swift 3.0的成果的一部分。
Clarity at the point of use is your most important goal. Code is read far more than it is written. 用法的清晰是最重要的目标。阅读代码远远比写重要。
Clarity is more important than brevity. Although Swift code can be compact, it is anon-goal to enable the smallest possible code with the fewest characters. Brevity in Swift code, where it occurs, is a side-effect of the strong type system and features that naturally reduce boilerplate. 清晰比简洁更重要。尽管 Swift 代码可以很简洁,但是目标却不是以最可能少的单词完成尽少量的代码。Swift 代码中,简洁它是存在的,但也仅仅是强类型系统和特性自然而然产生的意外效果。
Write a Documentation Comment for every method or property in Swift’s dialect of Markdown. Ideally, the API’s meaning can be understood from its signature and its one- or two-sentence summary: 为每个方法和属性书写注释,并符合Swift 版的Markdown语法,通过签名和一两句概要即可理解 API 的含义。
1 | /// Returns the first index where `element` appears in `self`, |
Insights gained by writing documentation can have such a profound impact on your API’s design that it’s a good idea to do it early on. 通过写文档获得的洞察力,可以对你设计 API 产生巨大的影响,因此最好今早的开始做。
If you are having trouble describing your API’s functionality in simple terms, you may have designed the wrong API. 如果你尝试用简单的术语来描述的你的 API 的功能时都有问题,可能你设计的错误的 API。
For example, consider a method that removes the element at a given position within a collection 例如,考虑一个方法用来删除集合类的指定位置的元素
1 | public mutating func removeAt(position: Index) -> Element |
used as follows: 用法如下
1 | empliyees.removeAt(x) |
If we were to omit the word At
from the method name, it could imply to the reader that the method searches for and removes an element equal to x
, rather than using x
to indicate the position of the element to remove. 如果省略方法名中的单词At
,对于读者将意味着这个方法可以搜索并移除一个等于x
的元素,而非表示使用x
定位将要移除的元素的位置。
1 | employees.remove(x) // unclear: are we removing x? |
More words may be needed to clarify intent or disambiguate meaning, but those that are redundant with information the reader already possesses should be omitted. In particular, omit words that merely repeat type information: 可能需要更多单词来明确意图或消除歧义,但是多余的信息读者可能会忽略。尤其要删除那些仅仅指明类型信息的单词。
1 | public mutating func removeElement(member: Element) -> Element? allViews.removeElement(cancelButton) |
In this case, the word Element adds nothing salient at the call site. This API would be better: 本例中,Element 这个单词在调用时并没有显著的作用。下面这个 API 可能更好。
1 | public mutating func remove(member: Element) -> Element? allViews.remove(cancelButton) // clearer |
Occasionally, repeating type information is necessary to avoid ambiguity, but in general it is better to use a word that describes a parameter’s role rather than its type. See the next item for details. 个别情况下,重复类型信息室必要的,以避免歧义。但通常来说,使用表示参数的作用单词要比类型信息的单词的更好。下一条项目将会详细讲解。
Especially when a parameter type is NSObject
, Any
, AnyObject
, or a fundamental type such Int
or String
, type information and context at the point of use may not fully convey intent. 尤其是当参数类型是NSObject
,Any
,AnyObject
或者最基本的类型如 Int
或 String
,这时候类型信息和使用时的上下文可能不能完全表达出意图。
1 | func addObserver(_ observer: NSObject, forKeyPath path: String) |
To restore clarity, precede each weakly-typed parameter with a noun describing its role: 回归到清晰,优先添加描述作用的名词来命名弱类型参数
1 | func addObserver(_ observer: NSObject, forKeyPath path: String) |
x.reverse()
, x.sort()
, x.append(y)
. 变异的方法应该使用命令式的动词短语。x.distanceTo(y)
, i.successor()
. 非变异的方法尽可能的使用名词短语。Imperative verbs are acceptable when there is no good alternative that reads as a noun phrase: 必要的使用动词也是可接受的,当没有其他好的可以读起来像一个名字短语的选项。
1 | let firstAndLast = fullName.split() // acceptable |
x.sort()
and x.append(y)
are x.sorted()
and x.appending(y)
. 与变异之对应的非变异自己的变异方法通常是动词加“ed/ing”Often, a mutating method will have a non-mutating variant returning the same, or a similar, type as the receiver. 通常,一个非变异自己的变异的方法返回值是一个相同或者相似类型。
Prefer to name the non-mutating variant using the verb’s past tense (usually appending “ed”): 偏爱用动词过去式(通常是结尾添加“ed”)命名一个非变异体
1 | /// Reverses `self` in-place. |
When adding “ed” is not grammatical because the verb has a direct object, name the non-mutating variant using the verb’s gerund form (usually appending “ing”): 当因为及物动词添加“ed”不和语法时,就使用动名词形式(通常结尾添加“ing”)来命名
1 | /// Strips all the newlines from \`self\` |
x.isEmpty
, line1.intersects(line2)
. 非变异的布尔方法和属性应使用断言作为接收器。Collection
). Protocols that describe a capability should be named using the suffixes able
,ible
, or ing
(e.g. Equatable
, ProgressReporting
). 描述是什么的协议用名词。描述能力的用 able
,ible
, or ing
等后缀。Term of Art
noun - a word or phrase that has a precise, specialized meaning within a particular field or profession. 一个单词或短语,有明确的特定的含义在某一特定领域或专业。
The only reason to use a technical term rather than a more common word is that it precisely expresses something that would otherwise be ambiguous or unclear. Therefore, an API should use the term strictly in accordance with its accepted meaning.
Don’t surprise an expert: anyone already familiar with the term will be surprised and probably angered if we appear to have invented a new meaning for it.
Don’t confuse a beginner: anyone trying to learn the term is likely to do a web search and find its traditional meaning.
>The intended meaning for any abbreviation you use should be easily found by a web search.
译者注:#Swift3 Remove the ++ and – operators
Author: Chris Lattner https://github.com/apple/swift-evolution/blob/master/proposals/0004-remove-pre-post-inc-decrement.md
Document the complexity of any computed property that is not O(1). People often assume that property access involves no significant computation, because they have stored properties as a mental model. Be sure to alert them when that assumption may be violated. 指出任何复杂度非O(1)的计算属性。因为人们通常假设属性访问并非复杂计算量。
Prefer methods and properties to free functions. Free functions are used only in special cases. 偏爱方法和属性,而非相对独立的函数。
Follow case conventions: names of types, protocols and enum cases are UpperCamelCase
. Everything else is lowerCamelCase
. 遵循驼峰大小写法:类型,协议和枚举用大驼峰法,其余小驼峰法。
Methods can share a base name when they share the same basic meaningbut operate on different types, or are in different domains. 方法可以共用一个通用名,如果均指一个基本含义时,用于不同的类型或者不同的作用域。
For example, the following is encouraged, since the methods do essentially the same things:
1 | extension Shape { |
3.2.1. Take advantage of defaulted arguments when it simplifies common uses. Any parameter with a single commonly-used value is a candidate for defaulting. 充分利用参数的默认值。
3.2.2. Prefer to locate parameters with defaults towards the end of the parameter list. Parameters without defaults are usually more essential to the semantics of a method, and provide a stable initial pattern of use where methods are invoked. 尽量含默认值参数置于参数列表后面。
3.2.3. Prefer to follow the language’s defaults for the presence of argument labels 遵循语言习惯填写外部参数标签。
In other words, usually: 换言之
First parameters to methods and functions should not have required argument labels. 第一参数不必指明外部参数。
Other parameters to methods and functions should have required argument labels. 后面的外部参数必须填写。
All parameters to initializers should have required argument labels. 所有涉及初始化的参数均需外部参数。
The above corresponds to where the language would require argument labels if each parameter was declared with the form: 如果符合上述需要外部参数标签,应该向下面这么声明
swift identifier: Type
>译者注:参看 http://stackoverflow.com/questions/24815832/when-are-argument-labels-required-in-swift
There are only a few exceptions: 也有例外
In initializers that should be seen as “full-width type conversions,” the initial argument should be the source of the conversion, and should be unlabelled. 包含全角的类型转换的初始化应该使用原始指,而且不包含外部参数标签。
1 | extension String { |
When all parameters are peers that can’t be usefully distinguished, none should be labelled. Well-known examples include min(number1, number2)
andzip(sequence1, sequence2)
. 如果所有参数是平等不易区分重要性,不用加外部参数标签。
When the first argument is defaulted, it should have a distinct argument label. 如果第一个参数是值可空,那么就应该添加一个清晰的外表参数标签。
1 | extension Document { |
As you can see, this practice makes calls read correctly regardless of whether the argument is passed explicitly. If instead you omit the parameter description, the call may incorrectly imply the argument is the direct object of the “sentence:”
1 | extension Document { |
If you attach the parameter description to the function’s base name, it will “dangle” when the default is used:
1 | extension Document { |
Any
, AnyObject
, and unconstrained generic parameters) to avoid ambiguities in overload sets. 特别注意不受约束类型的多态。For example, consider this overload set:
1 | struct Array { |
These methods form a semantic family, and the argument types appear at first to be sharply distinct. However, when Element
is Any
, a single element can have the same type as a sequence of elements:
1 | var values: [Any] = [1, "a"] values.append([2, 3, 4]) // [1, "a", [2, 3, 4]] or [1, "a", 2, 3, 4]? |
To eliminate the ambiguity, name the second overload more explicitly: 为了排除歧义,重新命名时更加明确含义。
1 | struct Array { |
Notice how the new name better matches the documentation comment. In this case, the act of writing the documentation comment actually brought the issue to the API author’s attention.
Our Markdown processor gives special treatment to the following bullet list keywords: Swift 版 Markdown 会特殊处理下面列出的关键词
-Attention: |
-Important: |
-Requires: |
---|---|---|
-Author: |
-Invariant: |
-See: |
-Authors: |
-Note: |
-Since: |
-Bug: |
-Postcondition: |
-Throws: |
-Complexity: |
-Precondition: |
-TODO: |
-Copyright: |
-Remark: |
-Version: |
-Date: |
-Remarks: |
-Warning: |
-Experiment: |
-Returns: |
Writing a great summary is more important than leveraging keywords. 写一个很棒的概要远比仅仅添加关键词重要的多。
You can omit separate documentation for each parameter and the return type if it wouldn’t add useful information beyond what’s already conveyed by the method signature and its summary line. For example: 除方法签名和概要信息外,如果不能添加有用的信息,就可以省略参数和返回类型的注释文档。
1 | /// Append `newContent` to this stream. |