第一节_基本知识

Mac和Xcode一些快捷键

command键:win键,option键:alt键
复制:com+c,粘贴:com+v,剪切:com+x
保存:com+s,撤销:com+z
运行程序:com+r
注释、取消注释:com+/
单步运行:F6

数据类型

  • 共有数值类型、字符串类型、布尔类型、枚举类型、合集类型五种
  • Swift中不强制要求定义类型,强制定义的只有常量let、变量var,let常量初始化后即不能再更改值

数值类型

有int、uint(无符号整数)、float、double四种基本数值类型

1
2
3
let n = 70     
let m = 50.0 //等号两边空格数必须相等
var n:Double = 50 //显示定义的类型

字符串类型

1
2
3
4
5
6
7
8
9
10
11
格式化字符串
var n = 50
var m = 60
var str1 = "I have \(n + m) pencils" // \(表达式)为格式化字符串
var str2 = "I have " + (String)(n + m) + " pencils" //效果相同

字符串的下标是String.index类型,不是int类型,不能直接用int作下标
startIndex:指向首字符;endIndex:指向末字符的后面;offsetby:偏移量。
let index1 = str.index(str.startIndex, offsetBy:1) //指向首字符后一字符
let index2 = str.index(str.endIndex, offsetBy:-1) //指向末字符
str2 = str[index1..<index2] //截取字符串,前闭后开区间

计算字符串长度:str2.count
比较字符串是否相等:== 和 !=
在Swift中字符串是值类型,复制传递的是字符串的值而非引用

布尔类型(Bool)

true/false

枚举类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enum DaysOfWeek{  //定义枚举类型
case Sunday
case Monday
case Tuesday
dase Wednesday
case Thursday
}
var day = DaysOfWeek.Sunday //用句号引出枚举项
day = .Monday //已确定day是DaysOfWeek类型,即不用再写,但句号必须写

enum ea : String{ //若枚举项有rawvalue,则必须写类型值
case a1 = "aa1"
case a2 = "aa2"
case a3 = "aa3"
}
let result = ea(rawValue:"aa1") //由raw值查枚举项,返回Option(ea.a1)
print(result!) //拆包,输出a1

合集类型(Collection)

  1. 数组和区间
  2. 字典(dict):键值对
  3. 集合(set):无序、不重复数组
    三种类型都可用xx.count表示元素数量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    //数组
    var an1 = [1,2,3,4]
    var an2 : [Int]
    an2 = [1,2,3,4]

    //区间
    an1[1..<3] //an[1],an[2]
    an1[1...3] //an[1],an[2],an[3]

    //字典
    var dic: [String : Int]
    dic = ["Red":0,"Green":1,"Bule":2]
    dic["Red"] //0

    //集合
    let s1 = Set([1,2,3])
    let s2 : Set<Int>
    s2 = [1,2,3]

可选值Optional

类型后加?为可选值,代表声明的变量可能为空(nil)

1
2
3
4
5
6
7
8
9
10
let dic = [0:"Red",1:"Blue",2:"Yellow"]
var color = dic[0] //color为String?类型,可能会返回nil值
print(color) //输出Optional("Red"),对"Red"封包了

if color! = nil{ //color不为空才执行操作
let actualColor = color! //对Optional("Red")拆包
}
else{
//统一在拆包阶段对nil进行处理,逻辑更清晰
}

第二节_语句

for-in循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for index in 1...5{
print(i)
} //条件不用加括号,但语句体要加中括号

//遍历数组
var an = [1,4,7,22,5]
for index in an{
print(index)
}

//遍历字典
let d = [0:"Red",1:"Green",2:"Blue"]
for key in d.keys{
print("\(key)->\(d[key])") //输出的是可选值
}

for(key,value) in d{
print("\(key)->\(value)") //输出正常值
}

switch-case

1
2
3
4
5
6
7
8
9
10
11
12
13
//没有break
//一个case可对应多个选择值
//最后必须加default

let x:Character = "1"
switch x {
case "a","b","d":
print("1")
case "s","e","p":
print("2")
default:
print("3")
}

函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
函数定义
func hello(name:String)->String{
return "Hello, " + name
}
调用
str="lrrr"
hello(name:str) //函数调用不能省略参数名称

//多返回值函数,用元组作返回值
func hello(n:Int)->(n1:Int,n2:Int){
let n1 = n+1
let n2 = n+2
return (n1,n2)
}
let total = hello(n:1)
print(total) //输出“(n1: 2, n2: 3)”

第三节_IOS开发

MVC模式

Model-View-Controller(模型-视图-控制器),面向对象的常用模式
模型:保存数据的类
视图:UI控件
控制器:把模型和控制器绑定在一起的类,以及实现中间逻辑层。
优点:可最大限度地分离这三类代码(数据、UI、逻辑),每个类只实现专一的功能。

控制类的绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
输出接口:
@IBoutlet weak war myButton: UIButton! //可与控件绑定的变量(Button按钮)

操作方法:
IBAction func doSomething(sender: UIButton){
//可响应控件所触发事件的函数,sender为控件类型
}

绑定:
在View视图上,(ctrl+左键)/右键拖住控件,拖向辅助编辑器中的viewControl.swift文件,
新建一个接口/方法,或绑定已有代码。
注:和已有代码绑定时,只有类型匹配才会出现绑定框。

一般流程:
控件A绑定Action,在绑定Action时指明响应什么Event,控件B绑定outlet,
在Action中对outlet进行操作,相当于对控件B操作。
Event触发时,执行Action,操作outlet,界面UI发生改变。

网络传输(HTTP协议)

HTTP协议分为请求头数据部分,请求头系统有内置属性,后台也是tomact服务器会自动处理
数据部分则是和后台自己约定的,比如提交到哪个文件夹,提交的文件叫什么名字等等。

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//先把HTTP数据部分写好(Data形式),方便后面传入request中
//name是要提交到哪个文件夹,filename为文件上传后的文件名
//7d4a661c433为分隔符,任意string串都可以。以'--'+分隔符开头,固定格式。
//'\r\n'表示换行,属性间是否换行也是固定格式。

//数据部分的开头,最后的要转成utf8格式
var postdata:Data = "--7d4a661c433\r\nContent-Disposition: form-data;name=\"uploadFile\";filename=\"lizec.jpg\"\r\nContent-Type:application/octet-stream\r\n\r\n".data(using: String.Encoding.utf8)!

//具体的数据部分,直接写入即可
postdata.append(UIImagePNGRepresentation(faceImg.image!)!)

//数据部分结尾
postdata.append("\r\n\r\n--7d4a661c433--\r\n".data(using: String.Encoding.utf8)!)

//定义请求函数,写成函数形式便于之后写回调函数
//postData为HTTP数据部分,webServerUrl为服务器的地址
func requestfun(_ postData:Data,webServerUrl:String){
let session:URLSession = URLSession.shared
let url:URL = URL(string:webServerUrl)! //将String形式的服务器地址转为URL形式

//定义HTTP请求头及相关属性,这部分是HTTP固定的属性
//用url初始化request,NSMutableURLRequest形式
let request:NSMutableURLRequest = NSMutableURLRequest(url:url)
request.timeoutInterval = 30
request.httpMethod = "POST"
request.httpBody = postData
request.setValue("UTF-8", forHTTPHeaderField: "Charsert")
//设置boundary,即分隔符
request.setValue("multipart/form-data;boundary=7d4a661c433", forHTTPHeaderField: "Content-Type")

//定义回调任务
//传入的request参数为NSMutableURLRequest形式的HTTP请求
//data为后端发来的数据(系统已自动将数据部分拆出来了)
let task = session.dataTask(with: request as URLRequest){ (data: Data?, response: URLResponse?, error: Error?) -> Void in
//有回调数据
if data != nil {
tempText = String(data:data!, encoding: String.Encoding.utf8)!
//print(tempText!)
sign = 1 //回调函数执行完

} else {
print("发送请求出错:\(String(describing: error?.localizedDescription))")
sign = 1
}
}

//执行回调任务
//系统定时查询后端有无response发过来,检测到response后即执行回调任务
//因此其他地方要等待回调函数执行才能更新,可while()循环检测标志位
task.resume()
}
}

//最后调用请求函数即可
requestfun(postdata, webServerUrl:"http://123.207.30.222:8080/WebHello/UploadServlet")

多线程操作

在GUI中,默认操作都是在主线程中完成的(对控件的操作,以及与控件无关的操作),因此如果有非常耗时的操作,就需要另开一个线程,放在其中执行,否则耗时的操作会使主线程阻塞,导致UI界面无法操作(点击按钮、输入文本等)。
而在分线程中,如果涉及到对UI界面的操作,就要再手动回到主线程中去操作相应控件,在swift中对应为DispatchQueue.main.async {//code}
swift中的线程操作,可通过GCD(Grand Central Dispatch)的方式完成,其将代码以队列(先进先出)的形式放入其他线程中执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//...code1
let queue = DispatchQueue.global(qos:.default)
queue.async {
//code3
DispatchQueue.main.async {
//在分线程中回到主线成中操作UI
upImgButton.isEnabled = false
}
}
//...code2

//代码说明:
//code1执行完后,建立线程队列queue,系统将块内的代码放入队列中,但并不会立即执行
//之后会执行code2,等当前线程时间片到了,才会去执行queue线程中的代码
//若没有并行设置,queue线程中的代码默认是顺序执行的

IOS图像格式

关于IOS的图像系统,有三种格式

- UIImage:在UIKit框架下显示的图像格式,用于UI显示,通过UIImageView.image调用或赋值
- CIImage:CoreImage框架操作的图像格式,CI框架的函数都是针对这个数据格式
- CGImage:位图格式,底层的图像存储格式,UI和CI本质都是对CGImage的封装
1
2
3
4
5
6
7
8
9
//三种图像的互相转换,UI和CI图像的转换都是通过CG间接完成的
UI->CG:UIImage.cgImage
UI->CI:CIImage(cgImage: UIImage.cgImage)

CG->UI:UIImage.init(cgImage: CGImage)
CG->CI:CIImage(cgImage: CGImage)

CI->UI:UIImage.init(cgImage: CIImage.cgImage)
CI->CG:CIImage.cgImage

人脸识别(系统库)

参考博文:https://www.jianshu.com/p/e371099f12bd

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//IOS内置的图像处理库,用于处理一些复杂的图像操作
import CoreImage

//人脸识别函数的传入参数之一
let imageOptions = NSDictionary(object: NSNumber(value: 5) as NSNumber, forKey: CIDetectorImageOrientation as NSString)

//未识别的原始照片
let personciImage = CIImage(cgImage: imageView.image!.cgImage!)

//定义精确度,High为较高的精度
let accuracy = [CIDetectorAccuracy: CIDetectorAccuracyHigh]

//定义人脸识别器
let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: accuracy)

//识别人脸,返回人脸数组
let faces = faceDetector?.features(in: personciImage, options: imageOptions as? [String : AnyObject])

//因为UI和CI两大框架的坐标系原点不相同
//UI为左上角,CI为左下角,因此要进行坐标变化
//否则人脸的位置坐标不对
let ciImageSize = personciImage.extent.size
//改变x,y延伸方向
var transform = CGAffineTransform(scaleX: 1, y: -1)
//改变原点位置
transform = transform.translatedBy(x: 0, y: -ciImageSize.height)

if let face = faces?.first as? CIFaceFeature {
//进行坐标系变换
//face.bounds返回识别的人脸CRect框,包括起点位置和图像宽、高
let faceImgBounds = face.bounds.applying(transform)
let sourceImageRef: CGImage = imageView.image!.cgImage!
//根据Rect截取人脸
let newCGImage = sourceImageRef.cropping(to: faceImgBounds)
var tempImage = UIImage.init(cgImage: newCGImage!)

//对截取的人脸图像进行压缩
let tempCGSize = CGSize(width:tempImage.size.width/4,height:tempImage.size.height/4)
UIGraphicsBeginImageContext(tempCGSize)
tempImage.draw(in: CGRect(x: 0, y: 0, width: tempCGSize.width, height: tempCGSize.height))

//因为图像会有向左旋转90度的bug,因此要进行修正
tempImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
tempImage = tempImage.fixOrientation()

//写入ImageView中
faceImg.image = tempImage
}
else {
let alert = UIAlertController(title: "提示", message: "未检测到人脸", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "确定", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}

// 修复图片旋转代码,扩展UIImage类
//根据图像的imageOrientation属性值来进行旋转
extension UIImage {
func fixOrientation() -> UIImage {
// if self.imageOrientation == .up {
// return self
// }

var transform = CGAffineTransform.identity

switch self.imageOrientation {
case .down, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: self.size.height)
transform = transform.rotated(by: .pi)
break

case .left, .leftMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0)
transform = transform.rotated(by: .pi / 2)
break

case .right, .rightMirrored,.up:
transform = transform.translatedBy(x: 0, y: self.size.height)
transform = transform.rotated(by: -.pi / 2)
break

default:
break
}

switch self.imageOrientation {
case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
break

case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: self.size.height, y: 0);
transform = transform.scaledBy(x: -1, y: 1)
break

default:
break
}

let ctx = CGContext(data: nil, width: Int(self.size.width), height: Int(self.size.height), bitsPerComponent: self.cgImage!.bitsPerComponent, bytesPerRow: 0, space: self.cgImage!.colorSpace!, bitmapInfo: self.cgImage!.bitmapInfo.rawValue)
ctx?.concatenate(transform)

switch self.imageOrientation {
case .left, .leftMirrored, .right, .rightMirrored:
ctx?.draw(self.cgImage!, in: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(size.height), height: CGFloat(size.width)))
break

default:
ctx?.draw(self.cgImage!, in: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(size.width), height: CGFloat(size.height)))
break
}

let cgimg: CGImage = (ctx?.makeImage())!
let img = UIImage(cgImage: cgimg)

return img
}
}


Post Date: 2018-01-27

版权声明: 本文为原创文章,转载请注明出处