17.面向对象
懒加载
懒加载的格式如下 :
------------
ViewController.swift ------------
class ViewController:
UIViewController {
/**
`
懒
`
加载
,
本质上是一个闭包
第一次访问属性时
,
会执行后面的代码
,
将闭包的
`
结果
`
保存在
person
属性中
下次再访问
,
就不会再执行闭包
!
如果没有
lazy,
会在
initWithCoder
方法中被调用
,
当
`
二进制
`
的
storyboard
被还原成视图控制器对象之后
,
就会被调用
提示
:
在开始的时候
,
可以先尝试记忆语法
!
*/
// 1.
懒加载的简单写法
lazy
var demoPerson2:
HMPerson =
HMPerson()
// 2.
懒加载写法
lazy
var person:
HMPerson = {
print(
"
懒加载
")
return
HMPerson()
}()
// --
以下代码仅供参考
,
演示闭包
--
// 1.
定义闭包
let personFunc = { () -> (
HMPerson)
in
print(
"
懒加载测试
...")
return
HMPerson()
}
// 2.
测试懒加载
lazy
var demoPerson:
HMPerson =
self.
personFunc()
//
视图加载完成
override
func viewDidLoad() {
super.
viewDidLoad()
print(
demoPerson2)
}
//
屏幕的触摸事件
override
func touchesBegan(touches:
Set<
UITouch>, withEvent event:
UIEvent?) {
print(
demoPerson2)
}
}
18.getter 方法 和 lazy 懒加载的对比
------------
HMPerson.swift ------------
class HMPerson:
NSObject {
// -- getter & setter
方法在
swift
中极少用
,
仅供参考
// OC
中利用
getter
方法
,
编写懒加载
,
而
swift
中提供了
lazy
//
如果不希望暴露的方法或者属性
,
都需要用
private
保护起来
!
private
var _name:
String?
var name:
String? {
get {
//
返回
_
成员变量
的值
return
_name
}
set {
//
使用
_
成员变量
记录新的数值
_name = newValue
}
}
var name2:
String?
//
完成的效果与上面一样
// -- read only
属性
,
只写
getter
方法
// swift
中
, get only
属性
,
只写
getter
方法
,
可以进行多次赋值
,
同时也成为
`
计算
`
型属性
var title:
String? {
get {
return
"Mr " + (
name ??
"")
}
}
/**
只读属性的简写方法
-
如果属性的
`
修饰
`
方法
,
只提供
getter ,
那么
get {}
可以省略
每次调用的时候
,
都会执行
{}
中的代码
, `
结果取决于其他属性或者原因
`
1>
每次都要计算
,
浪费性能
-
如果计算量很小
,
可以使用
2>
不需要开辟额外的空间
*/
var title2:
String? {
return
"Mr 222" + (
name ??
"")
//
特别注意
: getter
方法
,
只读属性
,
可以多次赋值
}
/**
懒加载
-
第一次调用的时候
,
执行闭包
,
并且在
title3
中保存闭包执行结果
再次调用
,
不再执行闭包
,
而是直接返回之前计算的结果
!
1>
只需要计算一次
2>
需要开辟单独的空间来保存计算结果
3>
闭包的代码
,
再也不会被调用
!
4>
如果计算量很大
,
需要提前准备
*/
lazy
var title3:
String? = {
/**
闭包
:
是一个提前准备好的代码
,
在需要的时候执行
使用
: self.
用于闭包在执行时
,
准确的绑定对象
注意
:
闭包中的
self.
是不能省略的
!
*/
return
"Mr 333" + (
self.
name ??
"")
}()
}
------------
ViewController.swift ------------
override
func viewDidLoad() {
super.
viewDidLoad()
let person =
HMPerson()
person.
name =
"
张三
"
print(person.
name)
// getter & setter
方法
-> Optional("
张三
")
print(person.
title2)
// getter
方法
(get only) -> Optional("Mr 222
张三
")
print(person.
title3)
// lazy
懒加载
-> Optional("Mr 333
张三
")
print(
"-----------")
person.
name =
nil
person.
name =
"
李四
"
print(person.
title2)
// getter
方法
-> Optional("Mr 222
李四
")
被修改
print(person.
title3)
// lazy
懒加载
-> Optional("Mr 333
张三
")
未修改
(
即使清空
,
也不能修改
)
}
19.Xcode 7 网络访问
ATS
应用传输安全
官方文档描述如下
:
App Transport Security (ATS) lets an app add a declaration to its Info.plist file that specifies the domains with which it needs secure communication. ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt. You should adopt ATS as soon as possible, regardless of whether you’re creating a new app or updating an existing one.
If you’re developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible.
If you’re developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible.
程序运行报错信息如下 :
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
设置强制访问 :
<
key
>
NSAppTransportSecurity
</
key
>
<
dict
>
<!--Include to allow all connections (DANGER)-->
<
key
>
NSAllowsArbitraryLoads
</
key
>
<
true
/>
</
dict
>
OC 网络测试代码如下
------------
HMNetworkController.m ------------
- (
void)viewDidLoad {
[
super
viewDidLoad];
[[[
NSURLSession
sharedSession]
dataTaskWithURL:url
completionHandler:^(
NSData *
_Nullable data,
NSURLResponse *
_Nullable response,
NSError *
_Nullable error) {
//
反序列化
id result = [
NSJSONSerialization
JSONObjectWithData:data
options:
0
error:
NULL];
NSLog(
@"%@", result);
}]
resume];
}
swift 中的 JSON 反序列化
JSON
序列化
override
func viewDidLoad() {
super.
viewDidLoad()
// `_`
表示忽略
session
默认超时时长
60s
NSURLSession.
sharedSession().
dataTaskWithURL(url!) { (data,
_,
_) ->
Void
in
/**
JSON
是一个特殊格式的字符串
反序列化
- `throws` 2.0
的语法
,
捕获异常
注意点
: OC
中的安慰枚举的方式改为数组的方式设置
[
值
1,
值
2]
try!
程序员要负责
,
如果数据格式不正确
,
会崩毁
!
*/
let result =
try!
NSJSONSerialization.
JSONObjectWithData(data!, options: [
NSJSONReadingOptions.MutableContainers,
NSJSONReadingOptions.MutableLeaves])
print(result)
}.
resume()
}
网络中的 do catch 语法
override
func viewDidLoad() {
super.
viewDidLoad()
NSURLSession.
sharedSession().
dataTaskWithURL(url!) { (data,
_,
_) ->
Void
in
do {
let result =
try
NSJSONSerialization.
JSONObjectWithData(data!, options: [])
print(result)
}
catch {
//
如果反序列化失败
,
能够捕获到
JSON
失败的准确原因
,
而不会崩溃
print(error)
}
}.
resume()
}
//
正确信息返回
{
weatherinfo = {
Radar = "JC_RADAR_AZ9010_JB";
SD = "26%";
WD = "\U4e1c\U5357\U98ce";
WS = "2\U7ea7";
WSE = 2;
city = "\U5317\U4eac";
cityid = 101010100;
isRadar = 1;
njd = "\U6682\U65e0\U5b9e\U51b5";
qy = 1012;
temp = 10;
time = "10:25";
};
}
// 模拟JSON 格式错误
override
func viewDidLoad() {
super.
viewDidLoad()
NSURLSession.
sharedSession().
dataTaskWithURL(url!) { (data,
_,
_) ->
Void
in
// JSON
是一个特殊格式的字符串
|
格式不正确
, json
不是数组
let jsonStr =
"\"hello\", \"world\"]"
let jsonData = jsonStr.
dataUsingEncoding(
NSUTF8StringEncoding)
do {
let result =
try
NSJSONSerialization.
JSONObjectWithData(jsonData!, options: [])
print(result)
}
catch {
//
如果反序列化失败
,
能够捕获到
JSON
失败的准确原因
,
而不会崩溃
print(error)
}
}.
resume()
}
错误信息输出
:
程序没有奔溃
!
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
20.网络中的 guard else 语法
override
func viewDidLoad() {
super.
viewDidLoad()
NSURLSession.
sharedSession().
dataTaskWithURL(url!) { (data,
_,
_) ->
Void
in
// JSON
格式错误测试
let jsonStr =
"\"heallo\", \"world\"]"
let jsonData = jsonStr.
dataUsingEncoding(
NSUTF8StringEncoding)
guard
let result =
try?
NSJSONSerialization.
JSONObjectWithData(jsonData!, options: [
NSJSONReadingOptions.MutableContainers,
NSJSONReadingOptions.MutableLeaves])
else {
print(
"
反序列化失败
")
return
}
print(result)
}.
resume()
//
但一定要记得开启
}
错误信息输出
:
程序没有奔溃
!
反序列化失败
补充:
17.懒加载—实际上是一个闭包: lazy关键字
懒加载的几种写法:
1.
lazy
var
person:
Person
=
Person
()
2.
lazy
var
person2:
Person
= {
let p = Person ()
// 设置 p 的属性
// ...
return p
let p = Person ()
// 设置 p 的属性
// ...
return p
}()
3.
lazy
var
person3 = { () ->
Person
?
in
return Person ()
return Person ()
}()
特点:在第一次调用时候,执行闭包,执行完成之后,会把值保存在前面的变量中,闭包代码永远都不会再次执行,
注意:懒加载的方法和OC的方法区别:
1.
在第一次调用
person3
的时候,会执行闭包中的代码,然后将结果保存在
person3
中
2.
一旦执行之后,闭包代码永远都不会再次执行!
3. person3 负责存储对象,闭包只是执行并且返回结果
例子;
18.构造函数中的getter 和 setter 方法:(几乎不用)
private : swift中 默认都是全局共享的,如果不希望暴露的属性和方法 ,用private修饰,提示:对于变量和方法,尽量都使用private, 在 Swift 中,如果使用 kvc 设置 private 属性,会崩溃
private var _name: String ? //属性
格式: var name: String ? {
get{
返回成员变量
return _name
}
set{
_name = newValue
使用成员变量记录数值,
newValue 就是设置过来的数值
}
}
19.只读属性:—计算型属性,本身不存储内容,通过计算获得结果,例子:
计算型属性可以简写:----直接return
例子:
计算型属性和懒加载有什么区别:
//
计算型属性可以简写
-
直接
return
//
本身不存储内容,通过计算获得结果
// 不需要为 title2 分配空间,每次临时计算
// 消耗 CPU ,节省内存
var title2: String {
return "Mr2222 " + ( name ?? "" )
// 不需要为 title2 分配空间,每次临时计算
// 消耗 CPU ,节省内存
var title2: String {
return "Mr2222 " + ( name ?? "" )
}
懒加载 —存储型属性
//
在第一次调用的时候,执行闭包,将计算结果保存在变量中
// 需要为 title3 分配空间 - 存储型属性
// 只计算一次,始终记录最初结果!
// 节省 CPU ,消耗内存!在 tableView 中要少用计算型属性!
lazy var title3: String = {
return "Mr333 " + ( self . name ?? "" )
// 需要为 title3 分配空间 - 存储型属性
// 只计算一次,始终记录最初结果!
// 节省 CPU ,消耗内存!在 tableView 中要少用计算型属性!
lazy var title3: String = {
return "Mr333 " + ( self . name ?? "" )
}()
didSet: 相当于OC中的set方法
// 模型
var
person:
Person
? {
didSet {
// didSet 会在 person 被设置完成之后调用,此时 person 已经有值
// 在 didSet 中,不需要考虑 _ 成员变量 = value
print ( person )
textLabel ?. text = person ?. name
detailTextLabel ?. text = person ?. phone
}
didSet {
// didSet 会在 person 被设置完成之后调用,此时 person 已经有值
// 在 didSet 中,不需要考虑 _ 成员变量 = value
print ( person )
textLabel ?. text = person ?. name
detailTextLabel ?. text = person ?. phone
}
}
20.json的反序列化:
let
url =
NSURL
(string:
"http://www.weather.com.cn/data/sk/101010100.html"
)
NSURLSession . sharedSession (). dataTaskWithURL (url!) { (data, _ , _ ) -> Void in
// JSON 本质上是特殊格式的字符串
let jsonString = "[\"hello\", \"world\"]"
let data = jsonString. dataUsingEncoding ( NSUTF8StringEncoding )
// 反序列化
// options 是枚举类型的 复数, Swift 中使用数组表示
// throw 抛出异常
// 方法 1 try? - 如果 json 格式不正确,返回 nil
// 方法使用的频率高!
let json1 = try ? NSJSONSerialization . JSONObjectWithData (data!, options: [.AllowFragments, .MutableContainers])
print (json1)
// 方法 2 try! - 如果 json 格式不正确,直接崩溃
// 实际开发不建议使用
// let json2 = try! NSJSONSerialization.JSONObjectWithData(data!, options: [])
// print(json2)
// 方法 3 try
// 能够捕获到错误信息,并且程序不回崩溃!
do {
let json3 = try NSJSONSerialization . JSONObjectWithData (data!, options: [])
print (json3)
} catch {
print (error)
}
NSURLSession . sharedSession (). dataTaskWithURL (url!) { (data, _ , _ ) -> Void in
// JSON 本质上是特殊格式的字符串
let jsonString = "[\"hello\", \"world\"]"
let data = jsonString. dataUsingEncoding ( NSUTF8StringEncoding )
// 反序列化
// options 是枚举类型的 复数, Swift 中使用数组表示
// throw 抛出异常
// 方法 1 try? - 如果 json 格式不正确,返回 nil
// 方法使用的频率高!
let json1 = try ? NSJSONSerialization . JSONObjectWithData (data!, options: [.AllowFragments, .MutableContainers])
print (json1)
// 方法 2 try! - 如果 json 格式不正确,直接崩溃
// 实际开发不建议使用
// let json2 = try! NSJSONSerialization.JSONObjectWithData(data!, options: [])
// print(json2)
// 方法 3 try
// 能够捕获到错误信息,并且程序不回崩溃!
do {
let json3 = try NSJSONSerialization . JSONObjectWithData (data!, options: [])
print (json3)
} catch {
print (error)
}
}.resume()
注意:
如果希望在程序中访问
OC
的对象,可以将
OC
的头文件放置在桥接头文件中