Swift学习笔记之A Swift Tour

Swift1.0的时候一时兴起学习了一下swift的基本语法,现在Swift已经更新到 2.1了,自己吧学到的也忘得差不多了,接下来重新复习一下。

今天先记录一下学习swift初见相关知识点。
微信公众账号lecoding同步更新

###1. if 条件语句

1
2
3
4
5
6
7
//---------------------- 1.1  if 联系 ------------------------/

var optionalString: String?
if let name = optionalString {
greeting="Hello, \(name)"
}
greeting // Hello

###1.2 使用 ?? 取代默认值

1
2
let wildcat="lecoding"
print("欢迎关注微信公众账号:\(optionalString ?? wildcat)")

//打印结果:欢迎关注微信公众账号:lecoding

1.3 switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
* 1. Switch 语句必须有Default选项
* 2. 不用加 break, 找到第一个匹配的分支自动结
*
**/
let animal = "wildcat"
switch animal {
case "dog":
print("It's a Dog!")
case "cat", "monkey":
print("its cat or monkey")
case let x where x.hasPrefix("wild"):
print("It's wild")
case "wildcat":
print("It is wildcat")
default:
print("I don't know")
}

//打印结果: It’s wild

1.4 for-in

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//1. 遍历
let numbersDictionary = [
"first": [12,23,1,23,34,43],
"second": [2,23,123,4,43],
"third": [82,-23,1,23,84,3]
]
var min=Int.max
for (key, numberlist) in numbersDictionary {
for number in numberlist{
if number < min{
min=number
}
}
}
print("\(min)")

//打印结果: -23

1
2
3
4
5
6
7
8
9
10
11
12
//2. `..<` 表示范围 , `..< `不包括上界, `...` 包括上界
var count=0
for i in 0..<4 {
count++
}
print("\(count)")
//打印结果:4
count=0
for i in 0...4 {
count++
}
print("\(count)")

//打印结果:5

##2. 函数

2.1 定义函数

1
2
3
4
func sayHello (name: String, words: String) -> String {
return "\(name) say:\" \(words)\"。"
}
sayHello("Lves", words: "欢迎关注公众号:lecoding")

//打印结果: Lves say:” 欢迎关注公众号:lecoding”。

2.2 函数返回多个值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func caculateStatistics(numbers: [Int]) -> (min: Int, max: Int, sum: Int){
var min = numbers[0]
var max = numbers[0]
var sum = 0
for num in numbers{
if num > max{
max = num
}else if num < min {
min = num
}
sum+=num
}
return (min, max, sum)
}

let result = caculateStatistics([23,34,45,4562,-23,0])
print(result.max) //打印结果:4562
print(result.min) //打印结果:-23
print(result.2) //打印结果:4641

swift中,函数支持嵌套,函数既可以当做另一个函数的参数,也可以当做另一函数的返回值
函数也是一种数据类型

2.3 函数嵌套

1
2
3
4
5
6
7
8
9
func functionInFunc() ->Int {
var num1 = 0
func add() {
num1++
}
add()
return num1
}
let result1 = functionInFunc() // 1

2.4 函数作为返回值

1
2
3
4
5
6
7
8
9
func getSumFunction()->((Int,Int)->Int) {
func getSum(num1: Int,num2: Int)->Int{
return num1 + num2
}
return getSum //返回函数名
}
var getSumFun=getSumFunction() //获得求和函数
let result2=getSumFun(10, 20)
result2 //30

2.5 函数作为参数

1
2
3
4
5
6
7
//第三个参数是一个函数类型的参数
func compareFunc(num1: Int ,num2 : Int ,paramFunc:(Int,Int)->Int)->Int {
return paramFunc(num1,num2)
}
//把求和函数传入进行求和
let compareResult=compareFunc(1, num2: 12, paramFunc: getSumFun)
// compareResult = 13

3. 闭包

函数是一种特殊的带有名字的闭包
匿名闭包使用in参数和返回值类型闭包体 分离。

3.1 闭包定义

1
2
3
4
5
6
7
8
var numArray1 = [10, 21, 2, 0, 65, 26]
//对数组中的每个元素取反后返回,原数组不会变
let numArray2 = numArray1.map({
(number:Int) -> Int in
return -number
})
//注释:数组.map() 对当前数组运用闭包内的规则然后返回一个新的数组
print(numArray1, numArray2)

打印结果: [10, 21, 2, 0, 65, 26] [-10, -21, -2, 0, -65, -26]

3.2 闭包简写

如果一个闭包的类型已知,比如作为一个回调函数,你可以忽略参数的类型返回值。单个语句闭包会把它语句的值当做结果返回。
上边的闭包你也可以写成下面这样:

1
2
3
4
5
let numArray3 = numArray1.map({number in
return -number
})

print(numArray1, numArray3)

打印结果: [10, 21, 2, 0, 65, 26] [-10, -21, -2, 0, -65, -26]

你可以通过 参数位置 而不是参数名字来引用参数——这个方法在非常短的闭包中非常有用。
当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。当一个闭包是传给函数的唯一参数,你可以完全忽略括号。

1
2
3
//数组排序
let sortedNumbers = numArray1.sort { $0 > $1 }
print(sortedNumbers)

打印结果: [65, 26, 21, 10, 2, 0]

4. 对象和类

####1.定义Person类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

class Person {
// MARK: - Properties
///姓名
var name: String
///年龄
var age:Int?
let hasParants:Bool = true

// MARK: - Lifecycle
//构造函数
init(name: String){
self.name = name
}
// MARK: - Private
func sayHello() ->String{
return "Hello, My Name is \(name),欢迎关注微信公众账号:lecoding。iOS开发文章实时更新!"
}
}

var per1 = Person(name: "Lves")
per1.age=24
var sayHi = per1.sayHello()
//"Hello, My Name is Lves,欢迎关注微信公众账号:lecoding。iOS开发文章实时更新!"

####2. 定义Person的子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

class Student: Person {
var className: String
init(name: String, className: String) {
self.className=className
super.init(name: name)
age = 20
}

override func sayHello() -> String {
return "I am a Student From class \(className)"
}
}

var stu = Student(name: "Lves", className: "一年级")
stu.age //20
stu.sayHello() //"I am a Student From class 一年级"


class Square {
var width : Float = 0.0

var perimeter: Float{
get {
return 4*width
}

set {
width = newValue/4.0
}
}

}

5. 枚举和结构体

###5.1 枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//1. 在swift中枚举可以包含方法
enum WeekType {
case Mon
case Tue, Wed, Thu, Fri
case Sat, Sun

func myDescription () -> String{
switch self {
case .Mon:
return "Monday"
case .Tue:
return "Tuesday"
case .Wed:
return "Wednesday"
case .Thu:
return "Thursday"
case .Fri:
return "Friday"
case .Sat:
return "Saturday"
case .Sun:
return "Sunday"
}
}
}
let weekday = WeekType.Thu // Thu
let desc = weekday.myDescription() // "Tuesday"

//枚举定义了类型之后,可以使用 .rawValue 查看原值
enum FromControllerType: String {
case First = "FirstController"
case Second = "SecondController"
}
let from = FromControllerType.First // First
print(from.rawValue)
//打印结果:"FirstController"

###5.2. 结构体

使用struct来创建一个结构体。结构体和类有很多相同的地方,比如方法和构造器。它们之间最大的一个区别就是结构体是传值,类是传引用

1
2
3
4
5
6
7
8
9
10
struct Week {
var weekday : WeekType
func myDescription() ->String {
return "My Weekday is \(weekday.myDescription())"
}

}

let structVar = Week(weekday: .Fri)
structVar.myDescription() // "My Weekday is Friday"

6. 协议和扩展

###6.1. 协议

1
2
3
4
5
protocol DescriptionProtocal {

var simpleDescrition: String { get }
mutating func adjust()
}

类、枚举、结构体都可以实现协议
类实现协议

1
2
3
4
5
6
7
8
class DescripClass: DescriptionProtocal {
var simpleDescrition:String {
return "I'm a Class"
}
func adjust() {

}
}

结构体实现协议

注意:声明SimpleStructure时候mutating关键字用来标记一个会修改结构体的方法。SimpleClass的声明不需要标记任何方法,因为类中的方法通常可以修改类属性(类的性质)。

1
2
3
4
5
6
7
8
9
struct DescripStruct: DescriptionProtocal {
var simpleDescrition: String = "I'm a Struct"
mutating func adjust() {
simpleDescrition += "123"
}
}
var structConformProtocal = DescripStruct()
structConformProtocal.adjust()
structConformProtocal.simpleDescrition // "I'm a Struct123"

枚举实现协议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
enum DescripEnum: DescriptionProtocal {
case Success, Error

var simpleDescrition: String {
get {
switch self {
case .Success:
return "You are Success"
case .Error:
return "You are Failure"
}
}
}
func adjust() {
}
}
var enumConformProtocal = DescripEnum.Success
enumConformProtocal.simpleDescrition //"You are Success"

protocol AbsoluteProtocal {
mutating func absolute() -> Double
}

###6.2 扩展

使用extension来为现有的类型添加功能,比如新的方法和计算属性。你可以使用扩展在别处修改定义,甚至是从外部库或者框架引入的一个类型,使得这个类型遵循某个协议。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//拓展 Double 类型同时实现 DescriptionProtocal、AbsoluteProtocal 两个协议

extension Double:DescriptionProtocal,AbsoluteProtocal {
var test:String{
return "demo"
}
var simpleDescrition:String {
return "The double value is: \(self)"
}
mutating func adjust() {
self = -self
}
mutating func absolute() ->Double {
return abs(self)
}
}

var doubleNumber:Double = 12.5
doubleNumber.simpleDescrition //"The double value is: 12.5"
doubleNumber.adjust() // -12.5

var oriNumber:Double = -100
var resultDouble=oriNumber.absolute() //取反
resultDouble // 100

oriNumber.test // "demo"

##7. 泛型

1
2
3
4
5
6
7
8
enum optionalValue<Type> {
case none
case other(Type)
}

var enumOfInt:optionalValue<Int> = .none
enumOfInt = .other(12)
print(enumOfInt)

打印结果:other(12)

1
2
3
4
5
6
7
8
9
10
11
func anyCommonElements <T: SequenceType, U: SequenceType where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, _ rhs: U) -> Bool {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1, 2, 3], [3])

微信公众账号同步更新:lecoding,你也可以扫描下方二维码和我一起学习Swift:

icon

Objective-C 预处理器(The Preprocessor)

Objective-C源文件在编译之前要先经过预编译器处理,然后再扔给LLVM处理、优化。Objectice-C编译器从源文件的输入到编译后的输出文件,处理过程分解后如下图:
123.png

如上图所示编译过程大体包括词法分析、语法分析、生成代码和优化、汇编链接,最后输出可执行的二进制文件。关于其中每个阶段的具体行为,我们就不做具体研究了,已经超出了我的能力范围(恨自己当年大学期间编译原理没有好好学啊),如果你感兴趣可以研究一下“龙书”《Compilers: Principles, Techniques, and Tools》,传说LLVM的作者Chris Lattner 曾经修炼了这本武功秘籍,还未毕业就被Apple盯上了。龙书真容如下(快膜拜):
234.png

今天我们主要看看和预处理器(词法分析部分)相关的内容。预处理器处理过程主要包括三个步骤:

  • 文本翻译: 将输入的源文件分成代码行,并进行一些翻译处理。
  • 记号转换: 将上一步的处理结果转换成记号语言。
  • 基于预处理语言的转换: 如果上一步结果中含有预处理语言元素,就会进行转换。

前两部是自动处理的,第三部要根据预处理语言函数进行处理,

##预处理语言

预处理语言对源文件进行转换主要包括文件引用、条件编译、宏展开。预处理语言定义了预处理指令和宏定义。预处理指令是预处理器执行的命令和编译器无关,宏定义只是一个具有名称的一段代码,在文件中会被预处理器替换成相应代码。

###指令
指令的格式: #指令名 指令参数 例如

#import "Student.h"
#define kBackColor  [UIColor redColor]

指令主要包括以下四种:

  • 头文件引用
  • 条件编译
  • 错误诊断
  • Pragma

#####头文件引用

头文件引用主要由#inlude#import 两种。每种又分为尖括号(<>)引用和双引号(" ")引用 。

  1. #inlude#import 的区别是: #import 不会造成重复引用,它会自己检查是否已经引用过,也可以防止递归包含。
  2. 尖括号(<>)引用与双引号(" ")引用的区别是
    • 双引号(" ")引用的文件,编译器会首先在存储源文件的同一目录下搜索,如果文件没有找到编译器会搜索默认目录(配置文件中配置的头文件引用目录)。
    • 尖括号(<>)引用 只会在默认目录下搜索。

#####条件编译
条件编译指令主要包括 (#if, #elif, #else, #endif, #ifdef, #ifndef) 利用他们可以选择性的编译代码。一个#if或者#ifdef 最后一定以#endif结束,中间写条件处理或者插入else指令。例如:

#ifdef, #ifndef

#ifdef DEBUG
       NSLog (@"File search complete. Found %i files", filecount");
#endif

#if, #elif, #else, #endif

#if constant_expression

#else

#endif

or

#if constant_expression

#elif constant_expression

#endif

#####诊断指令
诊断指令主要包括 #error#warning

#ifndef    ifOpen
#error "Not Open"
#endif

如果进入到#error指令,则编译器不会往下执行,如果编译到#warning指令,只会显示一个警告信息,还会继续编译。

#####Pragma指令

pragma 指令之一种编译器指令,它可以在特定平台下使用,像mark指令可以对代码进行分段标记,让代码更容易查找和跳转到指定位置。 我在自己的Controller中经常这样mark如下:

#pragma mark -
#pragma mark Life Cycle

#pragma mark -
#pragma mark Private Method

#pragma mark -
#pragma mark Action

#pragma mark -
#pragma mark Setter&Getter

###宏定义

宏定义就是对代码段起个名字,编译器编译之前预处理器会进行简单的字符串替换。宏定义可以进行简单的替换:

#define MY_CONSTANT 4

也可以定义一个带参数的代码段

#define SQUARE(x)  ((x) * (x))

因为宏定义默认只支持一样,如果要定义多行时每行结尾要加一个斜线(\),最后一行不用。

#define SWAP(a, b) \
a^=b;\
b^=a;\
a^=b;

宏定义枚举Block在`OC中经常使用。宏定义会在编译之前进行处理,而且一旦定义在其作用范围内都可以引用,可以提高编程效率。宏定义功能强大,当然宏定义也不能乱用它也存在确定,比如难以维护和查错。真机测试时定义太多的宏,当修改一个值就会重新编译好久。建议经常修改的值不要使用宏。一些宏能用常量替换的尽量使用常量。

原文链接:http://www.lvesli.com/?p=386 微信公众账号同步更新:lecoding
下面列出我自己项目中经常使用的宏定义:

//1. 打印日志
#ifdef DEBUG
#    define DLog(...) NSLog(__VA_ARGS__)
#else
#    define DLog(...)
#endif

//2. 获取屏幕 宽度、高度
#define kScreenWidth ([UIScreen mainScreen].bounds.size.width)
#define kScreenHeight ([UIScreen mainScreen].bounds.size.height)

//3. 颜色
#define RGB(r, g, b, a)  [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a]
#define HEXCOLOR(c)       [UIColor colorWithRed:((c>>16)&0xFF)/255.0f green:((c>>8)&0xFF)/255.0f blue:(c&0xFF)/255.0f alpha:1.0f]
//背景色  
#define BACKGROUND_COLOR [UIColor colorWithRed:242.0/255.0 green:236.0/255.0 blue:231.0/255.0 alpha:1.0]  
//清除背景色  
#define CLEARCOLOR [UIColor clearColor] 

//4.加载图片宏:
#define LOADIMAGE(file,type) [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:file ofType:type]]
//5. NavBar高度
#define NavigationBar_HEIGHT 44
//6. 获取系统版本
#define IOS_VERSION [[[UIDevice currentDevice] systemVersion] floatValue]
#define CurrentSystemVersion [[UIDevice currentDevice] systemVersion]

//7. 判断是真机还是模拟器
#if TARGET_OS_IPHONE
    //iPhone Device
#endif

#if TARGET_IPHONE_SIMULATOR
   //iPhone Simulator
#endif

//8. 设置View的tag属性
#define VIEWWITHTAG(_OBJECT, _TAG)    [_OBJECT viewWithTag : _TAG]

//9. GCD
#define BACK(block) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block)
#define MAIN(block) dispatch_async(dispatch_get_main_queue(),block)

//10. NSUserDefaults 实例化
#define USER_DEFAULT [NSUserDefaults standardUserDefaults]

本博客也会在 lecoding 微信公众号中同步更新,欢迎大家订阅,有什么问题可以在此一起交流。公众号搜索: 乐Coding 或者 lecoding 或者微信扫描下方二维码:

icon

OS X 10.11 安装Cocoapods失败:Operation not permitted

系统升级到 OS X 10.11 (EI Capitan)的时候,当安装 CocoaPods 的时候提示如下的错误: Operation not permitted

一共有两种解决方案:

1.官方解决方案;

2.github解决方案,安装在其他目录(我采用的方案);

1.官方给出的解决方式是:自定义 GEM_HOME
$ mkdir -p $HOME/Software/ruby
$ export GEM_HOME=$HOME/Software/ruby
$ gem install cocoapods
[...]
1 gem installed
$ export PATH=$PATH:$HOME/Software/ruby/bin
$ pod --version
0.37.2  
Github 解决方案
$ sudo gem install -n /usr/local/bin cocoapods
$ pod setup

建议开通VPN安装会快点,如果你没有vpn也可以参照一下 唐巧 的一篇博客:链接

原文链接:http://lvesli.com

本博客也会在 lecoding 微信公众号中同步更新,欢迎大家订阅,有什么问题可以在此一起交流。公众号搜索: 乐Coding 或者 lecoding 或者微信扫描下方二维码:

https://github.com/Lves/lves.github.io/blob/master/images/icon.jpg?raw=true