标签:
Chris Lattner(克里斯·拉特纳)
开始着手 Swift 编程语言的设计工作Cocoa
和 Cocoa Touch
框架Smalltalk
的语法,全面改为句点表示法1.2
,测试版本是 2.0
会 Swift 开发
无疑会增加自身筹码《The Swift Programming Language》中文版 http://numbbbbb.gitbooks.io/-the-swift-programming-language-/
swifter 作者王巍,需要付费购买 http://onevcat.com
var i = 10
print(i)
i = 15
print(i)
let j = 20
// 常量一经定义不能自改数值
// j = 25
print(j)
OC: [[UIView alloc] init] -- [[UIView alloc] initWithFrame:]
Swift: UIView() -- UIView(frame: )
OC: [UIColor redColor];
Swift: UIColor.redColor()
枚举
OC: UIButtonTypeContactAdd
Swift: UIButtonType.ContactAdd
示例
// 1.创建UIView
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
customView.backgroundColor = UIColor.redColor()
// 2.创建一个按钮
let btn = UIButton(type: .ContactAdd)
btn.center = CGPoint(x: 50, y: 50)
// 3.将按钮添加到UIView上
customView.addSubview(btn)
// 定义变量
var i = 10
print(i)
i = 15
print(i)
let j = 20
// 常量一经定义不能自改数值
// j = 25
print(j)
小结
var
定义变量,设置之后可以修改let
定义常量,设置之后不可以修改;
print()
替代 OC 中的 NSLog
print
的性能更好定义 OC
对象
// 实例化视图
let v = UIView(frame: CGRectMake(0, 0, 100, 100))
// 设置背景颜色
v.backgroundColor = UIColor.redColor()
// 添加到根视图
view.addSubview(v)
Swift
中要实例化一个对象可以使用 类名()
的格式,与 OC
中的 alloc/init
等价OC
中的 initWithXXX
在 Swift
中通常可以使用 类名(XXX: )
找到对应的函数OC
中的 [UIColor redColor]
类方法,在 Swift
中通常可以使用 类名.XXX
找到对应的函数let
修饰 v
并且赋值,表示 该常量的内存地址不允许修改,但是可以修改其内部的属性
self.
常量&变量的使用原则:尽量先用 let,只有需要变的时候,再用 var,能够更加安全
let x = 10
let y = 10.5
let z: Double = 20
print(Double(x) + y) // 20.5
print(x + Int(y)) // 20
print(y + z) // 30.5
Swift
中会因为简单的 var
let
误以为 Swift
中的类型非常松散Swift
是对类型要求非常严格的一门语言,一个值永远不会被自动转换成其他类型
Double
类型Int
类型var 变量名: 类型 = 值
var number: Int = 30
number = 50
let number2: Int = 88
//number2 = 55
let number3 = 10.10
var number4: Int
number4 = 99
// 只有相同数据类型才能赋值
let number5: Int = Int(55.5) // 50
// 只有相同数据类型才能进行运算
let number6 = 10
let number7 = 88.8
let sum = Double(number6) + number7 // 98.8
// CGFloat --> double
let size = CGSize(width: 10, height: 10)
let number8 = 10.1
let sum2 = size.width + CGFloat(number8) // 20.1
let number1 = 10
let number2 = 10.1
元祖
let number3: (Int, Double, Int, Double) = (10, 10.1, 9, 44.40) //(.0 10, .1 10.1, .2 9, .3 44.4)
number3.0 // 10
number3.1 // 10.1
number3.2 // 9
number3.3 // 44.40
// 给元祖的元素起名称
let person = (name: "gcy", age: 30, score: 100.0) // (.0 "gcy", .1 30, .2 100)
person.name // "gcy"
person.age // 30
person.score // 100
// 提取元祖的数据
let (name, age, score) = ("gcy", 30, 100.0)
name
age
score
var i = 10
if i > 0 {
print("OK")
}
小结
Swift
中没有 C 语言中的非零即真
概念if
语句条件的 ()
可以省略{}
不能省略if
let number = 10
//if number = 10 // Swift有效的避免了这种问题
if number == 10
{
print(number)
}
let age = 16
if age >= 18
{
print("开网卡")
}else
{
print("回家找妈妈")
}
var a = 10
var b = 50
var result = a > b ? a : b
print(result) // 50
Swift
中的 三目
运算保持了和 OC 一致的风格print(age >= 18 ? "开网卡" : "回家找妈妈")
let score = 100
switch score
{
case 59:
print("不及格")
var num = 100
case 100:
print("满分")
default:
print("Other")
}
// 判断区间
switch score
{
case 0..<60: // 0~59
print("不及格")
case 60..<80: // 60~79
print("良好")
case 80..<100: // 80~99
print("优秀")
default:
print("满分")
}
let point = (100, 50)
// 判断元祖
switch point
{
case (0, 0):
print("原点")
case (50, 50):
print("中点")
case (100, 100):
print("右下角")
default:
print("Other")
}
// 取出元祖中的值
switch point
{
case (var x, var y) where x > y:
print(x)
print(y)
default:
print("Other")
}
5.可选类型
什么是可选类型:
一个变量可以有值也可以没有值, 我们就称之为可选类型
//var number: Optional<Int> = nil
//var number2: Int = nil
let number: Optional<Int> = 10
print(number!) // 10
let number2 = 10
let sum = number! + number2 // 20
let number3: Int? = 55
print(number3) // "Optional(55)\n"
/*
可选类型注意点:
* 在开发中一般情况下尽量不要强制解包一个可选类型, 否则会引发错误
*/
//let url = NSURL(string: "http://www.baidu.com")
//print(url)
//let request = NSURLRequest(URL: url!) // "Optional(http://www.baidu.com/)\n"
let url = NSURL(string: "http://www.baidu.com/")
print(url)
//let request = NSURLRequest(URL: url!)
if url != nil
{
let request = NSURLRequest(URL: url!)
}
// 可选绑定: 如果url不为nil, 系统内部就会自动将解包之后的值赋值给temp, 并且只有temp有值时才会执行{}中的代码
// Swift开发中推荐这种写法
if let temp = url
{
let request = NSURLRequest(URL: temp)
}
let url = NSURL(string: "http://www.baidu.com/")
if url != nil {
NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, _, _) -> Void in
print(NSString(data: data!, encoding: NSUTF8StringEncoding))
}).resume()
}
小结
在 Swift
中,不是所有的对象实例化方法都会返回值,在实际开发中需要注意实例化函数的返回类型,例如:
convenience init?(string URLString: String)
如果有 ?
表示改方法有可能无法实例化到正确的对象
可选项
,即有可能有值,也有可能没有值!
,指明改对象确实是存在的OC
的开发,尤其在日常练习时,会给定一个能够运行的值,而在实际运行时,一旦条件不满足,会直接闪退,这样用户体验会非常不好
Swift
的设计者考虑到因为对类型的强制要求,会让代码很难看,因此提供了一个变通的解决方案
if let url = NSURL(string: "http://baidu.com") {
NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, _, _) -> Void in
print(NSString(data: data!, encoding: NSUTF8StringEncoding))
}).resume()
}
小结
if let 常量 = 可选构造函数
的方式能够确保分支内部常量一定是有值的!
Swift
代码中的一个非常重要的使用技巧提示
Swift
提供了类型校验的手段,但是要写出 优雅
的 Swift 代码,还是需要多加练习的,否则一不小心就会出现分支嵌套层次很深的代码?
和 !
的选择,可以借助 Xcode 的辅助工具,但是强烈建议每次遇到提示时,要多加思考,反复揣摩演练3
var name: String? // nil
print(name?.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) // "nil\n"
//name = "gcy"
print(name?.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) // "nil\n"
print((name?.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) ?? 0)) //"0\n"
??
是一个非常有用的操作符,能够快速对 nil
进行判断nil
,则使用 ??
后面的值代替前面的 nil
值参与计算??
时,整个部分需要使用 ()
包装UITableView
的数据源方法中尤为重要for
// 传统写法
for var i = 0; i < 10; i++ {
print(i) // (10 times)
}
for
// 遍历 0 ~ <10
for i in 0..<10 {
print(i) // (10 times)
}
print("---") // "---\n"
// 遍历 0 ~ 10
for i in 0...10 {
print(i) // (11 times)
}
小结
Swift
中使用 in
关键字标示循环的范围0..<10
表示从0到90...10
表示从0到10特殊写法
for _ in 0...10 {
print("hello") // (11 times)
}
小结
_
忽略for var i = 0; i < 10; i++
{
print(i) // (10 times)
}
//死循环
for ;;
{
print("---") // (18657 times)
}
// Swift开发中推荐的for循环格式
for i in 0..<10
{
print(i) // (10 times)
}
var number = 0
while number < 10
{
print(number) // (10 times)
number++
}
var index = 0
repeat{
print(index) // (10 times)
index++
}while index < 10
let arr = ["zhangsan", "lisi"]
print(arr) // "["zhangsan", "lisi"]\n"
// 遍历每一个元素
for a in arr {
print(a) // (2 times)
}
// 像 OC 一样打印
print(arr as NSArray) // "(\n zhangsan,\n lisi\n)\n"
// 数组中保存的都是字符串
let arr = ["zhangsan", "lisi"]
// 数组中保存的是 NSObject
let arr1 = ["zhangsan", 1]
小结
NSObject
常见数组操作
// 定义只能保存字符串类型数组
var array: [String]
// 初始化数组
array = ["zhangsan"]
// 添加元素
array.append("lisi")
print(array) // "["zhangsan", "lisi"]\n"
// 删除元素
array.removeAtIndex(1) // "lisi"
print(array) // "["zhangsan"]\n"
// 删除所有元素
array.removeAll(keepCapacity: true) // []
print(array.capacity) // "2\n"
// 注意数组容量的变化
for i in 0..<10 {
array.append("\(i)") // (10 times)
print("\(array) --- \(array.capacity)") // (10 times)
}
// 实例化新的数组
var array2 = [String]() // []
array2.append("1") //["1"]
array2.append("2") // ["1", "2"]
// 拼接数组
array += array2 // ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "1", "2"]
print(array) // "["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "1", "2"]\n"
[String]()
let
定义的数组是不可变的
var
定义的数组是可变的
// 定义数组
//var arr: Array<Int>
//var arr: [Int]
//arr = [1, 2]
var arr = [1, 2]
// 1.遍历数组(取值)
arr[0]
for item in arr
{
print(item) // (2 times)
}
// 2.添加
arr.append(3)
arr
// 3.修改
arr[1] = 9
arr
// 4.删除
arr.removeAtIndex(0) // 1
arr // [9, 3]
// 5.合并
var arr1 = [3, 5, 7]
arr += arr1 // [9, 3, 3, 5, 7]
arr // [9, 3, 3, 5, 7]
// 6.Swift特殊
for item in arr[0..<2] // 0~1
{
print(item) // (2 times)
}
//arr.removeRange(Range(start: 0, end: 2))
//arr
// 通过观察可以发现Range其实就是一个半闭区间
arr.removeRange(0..<2) // [3, 5, 7]
arr // [3, 5, 7]
arr += arr1[0..<2] // [3, 5, 7, 3, 5]
8.字典
//var dict: Dictionary<String, String>
//var dict: [String: String]
var dict = ["name": "gcy", "age": "30"]
dict
// 企业开发中字典使用得最多的类型就是 [String: NSObject]类型
var dict2 = ["name": "gcy", "age": 30, "score": 99.9]
dict2
// 取值
dict2["name"]
// 修改
dict2["name"] = "wy"
dict2
// 增加
// 如果key存在就直接修改, 如果key不存在就会增加
dict2["rank"] = 1
dict2
// 删除
dict2.removeValueForKey("name")
dict2
// 遍历
// OC写法
for key in dict2.keys
{
print(dict2[key]) // (3 times)
}
// Swift写法
// 系统会自动将字典中的key赋值给元祖中的第一个遍历, 会自动将字典中的value赋值给元祖中的第二个遍历
for (xx, oo) in dict2
{
print(xx) // (3 times)
print(oo) // (3 times)
}
// 合并
var dict3 = ["name": "gcy", "age": 30]
var dict4 = ["score": 99.9]
// 注意点无论是数组还是字典, 只有相同类型才能赋值
for (key, value) in dict4
{
dict3[key] = value // 99.9
}
dict3 // ["score": 99.9, "age": 30, "name": "gcy"]
9.字符串
在 Swift 中绝大多数的情况下,推荐使用 String 类型
使用 String
的原因
String
是一个结构体,性能更高
String
目前具有了绝大多数 NSString 的功能String
支持直接遍历NSString
是一个 OC
对象,性能略差Swift
提供了 String
和 NSString
之间的无缝转换
遍历字符串
let str = "我要飞的更High"
for s in str {
print(s)
}
let str1 = "zhangsan"
let str2 = "lisi"
let i = 10
print(str1 + str2) // "zhangsanlisi\n"
print("\(str1) \(str2) \(i)") // "zhangsan lisi 10\n"
""
中使用 \(变量名)
的方式可以快速拼接字符串stringWithFormat
了for _ in 0...10 {
let str = String(format: "zhangsan - %04d", arguments: [arc4random_uniform(100)])
print(str) // (11 times) zhangsan - 0002
}
小结
String(format:...)
的方式String & Range 的结合
以下是超级费劲的代码
let str: String = "beixinke"
var subStr = str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex))
print(subStr) // "beixinke\n"
let str1: NSString = "beixinke" // "beixinke"
print(str1.substringWithRange(NSMakeRange(0, 3))) // "bei\n"
NSString *str = @"abc\0def";
NSLog("%@", str); // abc
let str = "abc\0def" // "abc?def"
print(str) // "abc?def\n"
// 遍历字符串
for c in str.characters
{
print(c) // (7 times)
}
// 字符串拼接
var str2 = "gcy"
str2 += str
str2 // "gcyabc?def"
// 字符串格式化
// 可以使用\()在字符串中插入任何数据
let name = "gcy"
let age = 30
let res = "name = \(name), age = \(age)"
res // "name = gcy, age = 30"
// 2015-10-09 03:04
let str3 = String(format: "%d-%02d-%02d %02d:%02d", arguments: [2015, 10, 9, 3, 4]) // "2015-10-09 03:04"
// 截取字符串
// 提示: 在Swift开发中, 我们经常需要将Swift的字符串转换为OC的字符串来操作, 并且Swift自身也意识到了这一点, 所以在OC字符串和Swift的字符串之间转换相当简单
let str4 = "beixinke"
//let str5: NSString = str4
//str5.substringToIndex(4)
//str5.substringWithRange(NSMakeRange(4, 2))
// as 就是把什么当做什么
(str4 as NSString).substringWithRange(NSMakeRange(4, 2)) // "in"
func sum(a: Int, b: Int) -> Int {
return a + b
}
小结
func 函数名(参数: 参数类型...) -> 返回值 { // 代码实现 }
-> 返回值
可以省略->
是一个很有意思的符号参数名的特殊处理
强制要求参数名
func sum1(x a: Int, y b: Int) -> Int {
return a + b
}
func sum2(a: Int, _ b: Int) -> Int {
return a + b
}
// 1.没有参数没有返回值
func say() -> Void
{
print("hi") // "hi\n"
}
say()
// 如果没有返回值可以简写
func say1() -> ()
{
print("hi") // "hi\n"
}
say1()
func say2()
{
print("hi") // "hi\n"
}
say2()
// 2.有参数没有返回值
// Swift2.0开始, 会自动将形参列表的第二个参数名称作为标签
// Swift2.0之前是没有这个特性的, 在Swift2.0之前如果需要显示标签需要在形参名称前面加上#
func sum(num1: Int, num2: Int)
{
print(num1 + num2) // "30\n"
}
sum(10, num2: 20)
// 3.没有参数有返回值
func getNumber() -> Int
{
return 998
}
print(getNumber()) // "998\n"
// 4.有参数有返回值
func sum2(num1: Int, num2: Int) -> Int
{
return num1 + num2
}
print(sum2(50, num2: 50)) // "100\n"
// 内部和外部参数
/*
* 默认情况下所有形参都是内部参数, 也就是说只能在函数内部使用
* 从Swift2.0开始会自动将形参列表的第二个参数名称作为标签, 也就是说从第二个参数开始, 参数的名称既是内部参数又是外部参数
* 如何指定外部参数?
*/
func sum3(num1: Int, y num2: Int)
{
print("num1 = \(num1), num2 = \(num2)") // "num1 = 10, num2 = 20\n"
print(num1 + num2) // "30\n"
}
//sum3(10, num2: 20)
sum3(10, y: 20)
// 默认参数
// 如果指定了默认值, 那么在调用方法的时候就可以不用传递数据, 如果不传递数据系统就会使用默认值, 如果传递了就会使用传递的值
// 在其它语言里面, 默认值一般情况只能是最后一个参数, 但是Swift可以写在任何位置
func joinString(str1: String, str2: String = "在", str3: String) -> String
{
return str1 + str2 + str3 // (2 times)
}
joinString("gcy", str2: "也在", str3: "bxk") // "gcy也在bxk"
joinString("wy", str3: "bxk") // "wy在bxk"
// 常量参数和变量参数以及inout参数
// 默认情况下所有形参都是常量参数, 不能在函数中修改形参的值
// 如果想在函数中修改形参的值, 那么必须把形参变为变量参数
// 和OC一样, 在函数中修改形参的值不会影响到外面实参的值
// 如果想在函数中修改形参之后影响实参, 那么必须把形参变为inout参数
//func swap(a: Int, b: Int)
//{
// let temp = a
// a = b // 不能修改常量参数
// b = temp
//}
//func swap(var a: Int, var b: Int)
//{
// print("a = \(a), b = \(b)")
// let temp = a
// a = b
// b = temp
// print("a = \(a), b = \(b)")
//}
func swap(inout a: Int, inout b: Int)
{
print("a = \(a), b = \(b)") // "a = 10, b = 20\n"
let temp = a // 10
a = b // 20
b = temp //10
print("a = \(a), b = \(b)") // "a = 20, b = 10\n"
}
var x = 10
var y = 20
print("x = \(x), y = \(y)") // "x = 10, y = 20\n"
swap(&x, b: &y)
print("x = \(x), y = \(y)") // "x = 20, y = 10\n"
// 可变参数
// 只要参数是可变参数, 就可以传递一个或多个值
// 在其它语言中一般情况下可变参数只能是最后一个形参, 而Swift中可以写在任意位置, 但是为了提高代码的阅读性, 还是建议写在最后
func sum4(nums: Int..., temp: Int) -> Int
{
var sum = 0 // 0
for i in nums
{
sum += i // (3 times)
}
return sum + temp // 16
}
sum4(1, 2, 3, temp: 10) // 16
// 函数嵌套
// 将一个函数写到另外一个函数的函数体中, 外面称之为函数嵌套
// 1.被嵌套的函数只能在父函数内部访问
// 2.被嵌套的函数可以访问外部的变量
// 应用场景: 两个函数之间依赖较强, 或者一个函数就只给另外一个函数使用
// 例如: 对数组排序是一个函数, 交换变量又是一个函数, 他们就可以使用函数嵌套
let value = 55 // 55
func test()
{
let number = 10 // 10
func demo()
{
print("----\(number), \(value)") // "----10, 55\n"
}
demo()
}
test()
class Person: NSObject {
var name: String?
// 如果属性是基本数据类型, 并且是可选类型, 系统不会自动分配存储空间
var age: Int = 0
// var name: String
// var age: Int
// Person()
override init() {
// 注意: 在构造方法中必须先初始化本类再初始化父类
name = "gcy"
age = 24
// 当我们重写一个类的构造方法时, 系统内部会悄悄的帮我们调用super.init()
super.init()
}
// 自定义构造方法
init(name: String, age: Int)
{
self.name = name
self.age = age
// 以下这一句代码, 能不写就不写
// super.init()
}
init(dict: [String: AnyObject])
{
// 注意:Swift中如果想在构造方法中使用KVC转换模型, 必须先调用 super.init()
super.init()
setValuesForKeysWithDictionary(dict)
}
// Swift中打印对象会调用下面这个属性
override var description: String {
// return "name = \(name), age = \(age)"
let property = ["name", "age"]
let dict = dictionaryWithValuesForKeys(property)
return "\(dict)"
}
}
class Person: NSObject {
var name: String?
var age: Int?
}
var _name: String?
var name: String? {
get {
return _name
}
set {
_name = newValue
}
}
在 Swift
中以上形式的 getter & setter 很少用
didSet
在 OC 中,我们通常希望在给某一个变量赋值之后,去做一些额外的操作
var length: Int? {
didSet {
timeStr = String(format: "%02d:%02d:%02d", arguments: [length! / 3600, (length! % 3600) / 60, length! % 60])
}
}
var timeStr: String?
var name: String?
{
// 在Swift开发中用以下两个方法代替OC中的重写setter方法
willSet{
print("赋值之前调用 \(newValue)")
}
didSet{
print("赋值之后调用 \(oldValue)")
}
}
var title: String {
get {
return "Mr " + (name ?? "")
}
}
getter
方法的属性被称为计算型属性,等同于 OC 中的 ReadOnly
属性var title: String {
return "Mr " + (name ?? "")
}
init(dict: [NSObject: AnyObject]) {
name = dict["name"] as? String
age = dict["age"] as? Int
}
deinit {
print("88")
}
值:
^(形参列表){
需要执行的代码
}
值:
{
(形参列表)->返回值类型
in
需要执行的代码
loadData ({ () -> () in
print("更新UI")
})
loadData ({
print("更新UI")
})
loadData (){
print("更新UI")
}
loadData {
print("更新UI")
}
func loadData(finished: ()->())
{
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print(NSThread.currentThread())
print("加载数据")
dispatch_async(dispatch_get_main_queue(), { () -> Void in
print(NSThread.currentThread())
finished()
})
}
}
能用最简单的就用最简单的写法
闭包的参数和返回值
示例:
1.在控制器的View上添加一个UIScrollview, 然后在UIScrollview上添加15个按钮, 让按钮平铺
2.要求创建UIScrollview以及按钮通过一个方法来创建
2.1并且按钮的个数必须通过闭包来指定
2.2并且如何创建按钮也必须通过闭包来指定(UIScrollview上面添加什么控件通过闭包传递)
/*
// 1.创建UIScrollview
let sc = UIScrollView(frame: CGRect(x: 0, y: 200, width: UIScreen.mainScreen().bounds.width, height: 50))
sc.backgroundColor = UIColor.redColor()
// 2.通过循环创建15个按钮
let count = 15
let width:CGFloat = 80
let height = sc.bounds.height
for i in 0..<count
{
let btn = UIButton()
btn.setTitle("标题\(i)", forState: UIControlState.Normal)
btn.frame = CGRect(x: CGFloat(i) * width, y: 0, width: width, height: height)
btn.backgroundColor = UIColor.greenColor()
// 3.将按钮添加到UIScrollview上
sc.addSubview(btn)
}
sc.contentSize = CGSize(width: CGFloat(count) * width, height: height)
// 4.将UIScrollview添加到控制器view上
view.addSubview(sc)
*/
let sc = createScrollview({ () -> Int in
return 20
}) { (index) -> UIView in
// let btn = UIButton()
// btn.setTitle("标题\(index)", forState: UIControlState.Normal)
// btn.backgroundColor = UIColor.greenColor()
let label = UILabel()
label.text = "标题\(index)!!!"
label.backgroundColor = (index % 2 == 0) ? UIColor.greenColor() : UIColor.purpleColor()
return label
}
view.addSubview(sc)
}
// 技巧: 在编写闭包代码时, 不管三七二十一先写上 ()->(), 然后再修改
func createScrollview(getNumber: ()->Int, createView: (index: Int)->UIView) -> UIScrollView
{
// 1.创建UIScrollview
let sc = UIScrollView(frame: CGRect(x: 0, y: 200, width: UIScreen.mainScreen().bounds.width, height: 50))
sc.backgroundColor = UIColor.redColor()
// 2.通过循环创建15个按钮
let count = getNumber()
let width:CGFloat = 80
let height = sc.bounds.height
for i in 0..<count
{
/*
let btn = UIButton()
btn.setTitle("标题\(i)", forState: UIControlState.Normal)
btn.frame = CGRect(x: CGFloat(i) * width, y: 0, width: width, height: height)
btn.backgroundColor = UIColor.greenColor()
*/
let subView = createView(index: i)
subView.frame = CGRect(x: CGFloat(i) * width, y: 0, width: width, height: height)
// 3.将按钮添加到UIScrollview上
sc.addSubview(subView)
}
sc.contentSize = CGSize(width: CGFloat(count) * width, height: height)
return sc
}
}
// 注意: 在设置闭包属性是可选类型时一定更要用一个()括住闭包的所有的类型, 否则只是指定了闭包的返回值是可选的
// 错误写法: var callback: ()->()?
var callback: (()->())?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
// OC中如何解决: __weak typeof(self) weakSelf = self;
// Swift中如何解决: weak var weakSelf = self
// 对应关系: __weak == weak __unsafe_unretained == unowned
// weak var weakSelf = self
loadData { [unowned self] () -> () in
print("被回调了")
// 在Swift开发中, 能不写self就不写slef
// 一般情况下只有需要区分参数, 或者在闭包中使用
// self.view.backgroundColor = UIColor.greenColor()
// weakSelf!.view.backgroundColor = UIColor.greenColor()
self.view.backgroundColor = UIColor.greenColor()
}
}
func loadData(finished: ()->())
{
callback = finished
// 1.加载数据
print("加载数据")
// 2.执行回调
finished()
}
// deinit 相当于OC中的dealloc方法
// 只要一个对象释放就会调用deinit方法
deinit
{
print("88")
}
}
lazy var listData: [String]? = {
()->[String]
in
print("---")
return ["gcy", "cyh", "wy", "lsl"]
}()
// 开发中这样写
lazy var listData2: [String]? = {
print("---")
return ["gcy", "cyh", "wy", "lsl"]
}()
lazy var listData3: [String]? = self.test()
func test() -> [String]
{
print("+++")
return ["gcy", "cyh", "wy", "lsl"]
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
print(listData3)
print(listData3)
print(listData3)
print(listData3)
}
+ (instancetype)shareNetworkTools
{
static NetworkTools *_instance;
// onceToken默认等于0, 只要执行一次之后就不等于0了, 原理是通过判断onceToken是否等于0决定是否需要执行block
static dispatch_once_t onceToken;
NSLog(@"%ld", onceToken);
dispatch_once(&onceToken, ^{
_instance = [[NetworkTools alloc] init];
});
return _instance;
}
而且苹果有统一的命名规范,但凡是单例统一是用shareInstance
/*
static var onceToken: dispatch_once_t = 0;
static var _instance: NetworkTools?
class func shareNetworkTools() -> NetworkTools {
print(onceToken)
dispatch_once(&NetworkTools.onceToken, {
_instance = NetworkTools()
})
return _instance!
}
*/
/*
static let _instance: NetworkTools = NetworkTools()
class func shareNetworkTools() -> NetworkTools {
return _instance
}
override init() {
print("++++++")
}
*/
static let shareInstance: NetworkTools = NetworkTools()
// 1.在Swift中遵守协议直接利用逗号隔开
class ViewController: UIViewController {
override func loadView() {
let tableView = UITableView()
tableView.dataSource = self
tableView.delegate = self
view = tableView
}
// MARK: - 懒加载
lazy var listData: [String]? = {
return ["gcy", "cyh", "wy", "sz", "lsl", "fbk"]
}()
}
// extension 相当于OC的 Category
extension ViewController: UITableViewDataSource, UITableViewDelegate
{
// MARK: - UITableViewDataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// TODO: 有问题, 开发中不应该这样写
return (listData?.count)!
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell")
if cell == nil
{
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
}
cell?.textLabel?.text = listData![indexPath.row]
return cell!
}
// MARK: - UITableViewDelegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(listData![indexPath.row])
}
}
17.变量类型推导
自动推导
的如果定义变量时,右侧代码具有歧义,可以在左侧以 :类型
指定变量的类型,例如:
// 个人推荐
let i: CGFloat = 10
也可以写成
var j = 10 as? CGFloat
如果某些方法返回的数据类型是 AnyObject
/AnyClass
,则需要在右侧使用 as 类型
表明类型,并且根据返回值是否是可选项
,添加 !
或者 ?
,例如:
let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
如果某些方法返回类型是 AnyObject
/AnyClass
,但是对象类型是动态生成的,也就是说,编码时同样无法确定改对象的准确类型,可以在左侧使用 : AnyObject
或者 : AnyClass
告诉编译器暂不处理,例如:
let cls: AnyClass = NSClassFromString(ns + "." + vcName)!
提示:as?
和 as!
是刚接触 swift 最令人烦恼的语法之一,苹果也在这个语法规则上多次做过调整,在学习时建议:
option + click
查看对象信息 /*
苹果也意识到了, Swift会不知不觉的形成多层嵌套, 然代码变得非常丑陋
所以Swift2.0的时候专门推出了一个条件语句(guard)来解决这个问题
格式:
guard 条件表达式 else {
需要执行的语句
return
}
特点: 只要条件为假才会执行else中的代码
作用: 用于过滤数据
对比if else 这哥们只有else{}没有if{}
*/
19.try catch
throw catch
是Xcode 7.0
对错误处理的一个非常大的变化
范例代码
// 2. 反序列化
// 1.获取json文件路径
let jsonPath = NSBundle.mainBundle().pathForResource("MainVCSettings.json", ofType: nil)
// 2.加载json数据
let jsonData = NSData(contentsOfFile: jsonPath!)
// 3.序列化json
do{
// throw是Xcode7最明显的一个变化, Xcode7之前都是通过传入error指针捕获异常, Xocode7开始通过try/catch捕获异常
let dictArray = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.MutableContainers)
// 遍历字典时候需要明确指明数组中的数据类型
for dict in dictArray as! [[String:String]]
{
// 由于addChildVC方法参数不能为nil, 但是字典中取出来的值可能是nil, 所以需要加上!
addChildViewController(dict["vcName"]!, title: dict["title"]!, imageName: dict["imageName"]!)
}
}catch{
print(error)
addChildViewController("HomeTableViewController", title: "首页", imageName: "tabbar_home")
addChildViewController("MessageTableViewController", title: "消息", imageName: "tabbar_message_center")
addChildViewController("DiscoverTableViewController", title: "发现", imageName: "tabbar_discover")
addChildViewController("ProfileTableViewController", title: "我", imageName: "tabbar_profile")
}
如果能确保代码执行正确,可以强行 try!
let array = try! NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers)
不过需要注意的是,一旦解析错误,程序会直接崩溃!
20.private
21.便利构造器
import UIKit
extension UIButton
{
class func create(imageName: String, backImageName: String) -> UIButton
{
let btn = UIButton()
// 1.设置背景图片
btn.setBackgroundImage(UIImage(named: imageName), forState: UIControlState.Normal)
btn.setBackgroundImage(UIImage(named: imageName + "highlighted"), forState: UIControlState.Highlighted)
// 2.设置普通图片
btn.setImage(UIImage(named:backImageName), forState: UIControlState.Normal)
btn.setImage(UIImage(named: backImageName + "highlighted"), forState: UIControlState.Highlighted)
btn.sizeToFit()
return btn
}
// 虽然以上方法可以快速创建一个UIButton对象, 但是Swift风格不是这样写的
// 在Swift开发中, 如果想快速创建一个对象, 那么可以提供一个便利构造器(便利构造方法--用于快速创建对象)
// 只要在普通构造方法前面加上一个convenience, 那么这个构造方法就是一个便利构造方法
// 注意: 如果定义一个便利构造器, 那么必须在便利构造器中调用指定构造器(没有加convenience单词的构造方法)
/*
定义便利构造器步骤:
1.编写一个构造方法
2.在构造方法前面加上 convenience
3.在构造方法中调用当前类的其他"非便利构造器"初始化对象
*/
convenience init(imageName: String, backImageName: String)
{
self.init()
// 1.设置背景图片
setBackgroundImage(UIImage(named: imageName), forState: UIControlState.Normal)
setBackgroundImage(UIImage(named: imageName + "highlighted"), forState: UIControlState.Highlighted)
// 2.设置普通图片
setImage(UIImage(named:backImageName), forState: UIControlState.Normal)
setImage(UIImage(named: backImageName + "highlighted"), forState: UIControlState.Highlighted)
sizeToFit()
}
}
标签:
原文地址:http://www.cnblogs.com/Free-Thinker/p/5400627.html