6.Swift协议|扩展|访问权限|异常调试|类型转换|运算函数|ARC|类类型初试化器|值类型初始化器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6.Swift协议|扩展|访问权限|异常调试|类型转换|运算函数|ARC|类类型初试化器|值类型初始化器相关的知识,希望对你有一定的参考价值。
1. 协议(Protocol):与OC之间唯一不同的是Swift中的协议不管是属性还时方法全部是必须实现的
/** protocol*/
protocol FullNamed {
/** 计算属性申明,只读的计算属性*/
var fullName:String { get }
}
/** 实现协议*/
struct Person:FullNamed {
/** 实现协议 可以把计算属性实现为存储属性,更改其本身的性质*/
var fullName: String = "abc"
}
/** 开发中的协议*/
protocol MyPotocol {
//计算属性的get set声明
var prop:Int {
get
set
}
var onlyRead:Int{ get }
//实例方法
func instanceMethod()->Int
//静态方法或者类方法
static func typeMethod()
}
class MyClass: MyPotocol {
var prop:Int = 10
var onlyRead:Int = 10
func instanceMethod() -> Int {
return 10
}
//此处按规范应该写static
class func typeMethod() {
print("class method")
}
}
var mc = MyClass()
mc.prop = 3
MyClass.typeMethod()
mc.instanceMethod()
mc.onlyRead = 5
mc.onlyRead
protocol SomeProtocol {
init(a: Int)
func test() -> Int
}
class parent {
init(a:Int){}
}
/** Swift中的协议的所有方法都必须实现,此处MyClass需要实现协议就需要对父类的方法进行改写,所以同时改写方法和实现required协议,前面使用 override 和 required关键字组合搭配:*/
class MyClass1: parent,SomeProtocol {
override required init(a:Int) {
super.init(a: 100) //改写内部实现方法依然为父类的方法。
}
func test()->Int {
return 1
}
}
//使用OC中的协议方式
@objc protocol ObjecProtocol {
func requiredMethod()
optional func optionalMethod()
}
class ObjectClass:ObjecProtocol {
@objc func requiredMethod() {
}
}
var r2 = Rect(x: 100, y: 200, w: 33, h: 2)
2.扩展(Extension),Swift中使用扩展的原则
不可以再扩展中定义存储属性,这是格式,定义了会报错,无法执行
可以再扩展中定义计算属性
extension Double{
//不可以在扩展中定义存储属性
//错误 var i = 10
//可以在扩展中定义计算属性
var km:Double {
return self/1000.0
}
var cm:Double {
return self * 100.0
}
/** 扩展一个方法实现四舍五入*/
func round()->Int{
//整数情况
return Int(self + 0.5)
}
}
350.0
print(350.5.km)
print(350.5.cm)
print(350.49.round())
print(350.50.round())
struct Point {
var x = 0.0
var y = 0.0
}
struct Size {
var w = 0.0
var h = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
}
var r = Rect()
//通过扩展一个带有四个参数的初始化器使得Rect在初始化的时候可以同时赋上四个值
extension Rect {
init(x:Double,y:Double, w:Double, h:Double){
self.origin = Point(x: x, y: y)
self.size = Size(w: w, h: h)
}
}
//其实上面的操作和OC里面的 -(id)initWithName:(NSString*)name andAge:(int) age{ if (self = [super init]; self.name = name, self.age = age)}功能是差不多的,只是表现形式不同而已
还可以通过扩展对系统类型的空间进行增加方法或者计算值属性
extension UIButton {
func show(){
print(self.tag)
}
}
3. 泛型(genericity): 字面意思理解就是广泛地被使用的类型,言外之意可以充当很多中类型。并且在赋值的时候它会根据系统的自动推倒公司变成制定的类型(Swift语言所期望的类型)
比如当我有很多个不同类型它门需要调换值,且实现逻辑一样。
函数+<T>指定T是一个泛型 T就代表各种类型的类型了
func swapTwoValues<T>(inout a:T,inout b:T) {
let temp = a
a = b
b = temp
}
swap(&str1, &str2)
str1
str2
/**类型的范型 Array<Double 属于一个类型> */
var arr:Array<Double> = Array()
struct Instack {
private var items = [Int]()
/**栈的特点后进先出*/
mutating func push(item:Int){
items.append(item)
}
mutating func pop(item:Int){
items.removeLast()
}
}
/**T属于一个类型函数,必须根据用户制定,通过Stack制定T(数组中元素的类型)*/
struct Stack<T> {
private var items = [T]() //一个任意类型的数组,当T被指定为什么类型,那么该数组就为什么类型]
/**这里利用栈的特定,后进先出 构造一个数组*/
mutating func push(item:T){
items.append(item)
mutating func pop(item:T){
items.removeLast()
}
}
var intStack:Stack<Int> = Stack()
var StringStack:Stack<String> = Stack()
4. 访问控制public表示在任何地方都能访问
internal表示在本项目能访问,为了限制类成员的作用阈在类的作用阈范围内,所以在类的内部不能使用public
private 职能在本.xxx文件中访问
/** 任何地方都可以访问*/
public class AClass {
}
/** 在本项目中访问*/
internal class IClass {
}
/**限于本文件中*/
private class CClass {
}
/** internal*/
class FClass {
//属性的权限不能高于类 public var = c = 2
internal var a = 10
private var b = 20
}
var fc:FClass = FClass()
fc.a
fc.b
5. 异常处理:非常有用,尤其在后续开发设计用户体验度相关问题的时候。**********************
/**异常处理(exception) ,这是OC常用的描述,而在我们的Swif提供了一类错误的支持,包括运行时抛出错误,捕捉错误,以及控制收回错误,使用了一个符合的ErrorType协议来表示。
1. 定义错误type,一般为枚举值,需要用一个值把程序中的问题表达出来
2. 根据不同的运算结果返回不同的ErrorType枚举值
3. 处理抛出的异常,通常采用 throws{ } 方法来判断不同的逻辑值后再调用throw选择性的抛出错误值
4. 处理抛出的异常,采用 do { try } catch 枚举值{ }catch枚举值{ },这样一个循环监听事件,持续的尝试去判断逻辑抛出一异常,然后执行接收异常。
*/
/** 自动售货机的Error*/
enum VendingMachineError:ErrorType {
case InvalidSelection //没有物品或者选择错误,选择物品错误
case OutOfStock //超出了范围,数量不够
case InsufficentFounds(required:Double) //前不够,差多少
}
/** 商品条目*/
struct Item {
var price:Double
var count:Int
}
/** 商品的数组*/
var inventory = ["可乐":Item(price: 1.25, count: 0),"??":Item(price: 7.5, count: 3),"??":Item(price: 0.75, count: 1)]
var amountDeposited = 1.0 //金额
/** 根据条件抛出异常*/
func vend(itemName:String)throws{
// guard 类似if,如果不是空就跳出else,守卫
guard var item = inventory[itemName]
else {
//抛出没有这个商品,选择错误
throw VendingMachineError.InvalidSelection
}
guard item.count > 0 else {
throw VendingMachineError.OutOfStock
}
if amountDeposited >= item.price {
//买东西
amountDeposited -= item.price
item.count--
}else {
throw VendingMachineError.InsufficentFounds(required: item.price - amountDeposited)
}
}
/** 处理抛出的异常*/
do{
try vend("可乐")
}catch VendingMachineError.InvalidSelection{
//执行可乐操作 时出现错误,就接收,此处写错误原因
print("选择错误")
}catch VendingMachineError.OutOfStock{
print("数量不足")
}catch VendingMachineError.InsufficentFounds(let ammoutRequired) {
print("还差\(ammoutRequired)")
}catch {
print("other unexecption")
}
6. 类型转换:
var d : Double = Double(a)
var s : String = "\(a)"
// is as
// 媒体
class MediaItem{
var name : String
init(name : String){
self.name = name
}
}
class Movie : MediaItem {
var director : String //导演
init(name: String, director : String) {
self.director = director
super.init(name: name)
}
}
// 歌曲
class Song : MediaItem {
var singer : String
init(name: String,singer : String) {
self.singer = singer
super.init(name: name)
}
}
var library : [MediaItem] = [Song(name: "周杰伦", singer: "青花瓷"),Movie(name: "夏洛特烦恼", director: "沈腾"),Movie(name: "美人鱼", director: "周星星"),Movie(name: "阿凡达", director: "爱谁谁"),Song(name: "北京北京", singer: "汪峰"),Song(name: "传奇", singer: "李键"),Song(name: "父亲", singer: "筷子兄弟")]
// 写一个程序 统计有多少个电影 多个少歌曲
var movieCount = 0
var songCount = 0
for item in library {
// is 判断某个对象是不是某个类型
// 类似于 OC 的 isKindOf
if item is Movie {
movieCount++
}
if item is Song {
songCount++
}
}
//上面采用了多态的方式 创建了一个MediaItem类型的libray,它里面有两种类型的元素,分别为Song和Moview
//下面我们通过从Library进行取出数据时,需要判断它的类型。
// as? 是类型转换 有可能成功有可能失败 返回可选值
for item in library {
// 成功就把item 变成Movie 类型并且赋值给movie 变量,通过?可选值搭配if else 确认类型
if let movie = item as? Movie {
print("电影名:\(movie.name) 导演:\(movie.director)")
}else if let song = item as? Song{
print("歌曲名:\(song.name) 歌手:\(song.singer)")
}
}
var m : Movie? = library[4] as? Movie
m?.name
var m : Movie? = library[4] as? Movie
m?.name
// as! 转换完是非可选值 如果转换失败报错
var m2 : Movie = library[2] as! Movie
m2.name
for item in library {
// is 判断某个对象是不是某个类型
// 类似于 OC 的 isKindOf
if item is Movie {
// 能进if 百分百是个Movie对象
let m = item as! Movie
m.name
m.director
}
if item is Song {
let s = item as! Song
}
}
// 了解
// Any 任意类型 swift中和 OC中所有的类型
// AnyObject 类型于OC id类型 NSObject,这样在我们不需要知道它类型的情况下,依然可以进行打印输出,避免程序报错。
var nsArray = NSArray(objects: "abc", "bcd", "def")
var nsArray2 : [String] = nsArray as! [String]
var nsArray3 : [String]? = nsArray as? [String]
var nsArray4 : Any = nsArray as! [String]
var nsArray5 : AnyObject? = nsArray as? [String]
7. 运算符函数: 顾命思议,就是使用运算符座为一个函数
// 运算符函数
//func + (a : Int, b : Int) -> Int {
// print("+ 号运算符函数")
// return 100
//}
var x = 100
var y = 200
var z = x + y
// 分数类
func + (f : Fraction, f2 : Fraction) -> Fraction {
let n = f.numberator * f2.denominator + f.denominator * f2.numberator
let d = f.denominator * f2.denominator
return Fraction(numberator: n, denominator: d)
}
// 写一个运算符函数 支持分数的相乘
func * (f : Fraction, f2 : Fraction) -> Fraction {
let n = f.numberator * f2.numberator
let d = f.denominator * f2.denominator
return Fraction(numberator: n, denominator: d)
}
struct Fraction {
var numberator : Int
var denominator : Int
init(numberator : Int, denominator : Int ){
self.numberator = numberator
self.denominator = denominator
}
func show(){
print("\(numberator)/\(denominator)")
}
}
var f = Fraction(numberator: 1, denominator: 2)
var f2 = Fraction(numberator: 1, denominator: 3)
var f3 : Fraction = f + f2
f3.show()
var f4 = f * f2
f4.show()
8. Swift的自动引用计数:和OC一样,无差异
import UIKit
class Person {
let name : String
init(name : String){
self.name = name
print("\(name) 被创建")
}
deinit{
print("\(name) 被销毁")
}
}
var person : Person?
var person2 : Person?
var person3 : Person?
person = Person(name: "张三")// 张三引用 1
person2 = Person(name: "李四")// 李四引用1
person3 = Person(name: "王五")// 王五引用 1
person3 = Person(name: "关羽")
// person3 = nil // 王五 引用 0
person2 = person // 李四的引用 0 张三 引用2
person = nil
person2 = nil
class A {
var b : B?
init(){}
deinit{ print("A 被销毁")}
}
class B {
// 不加weak 就是循环强引用 ,B 和 Aclass循环调用
weak var a : A?
init(){}
deinit{ print("B 被销毁") }
}
var a : A? = A()
var b : B? = B()
// 可选链 如果a为空不报错 就继续
a?.b = b
b?.a = a
a = nil
b = nil
9.类类型的初试化器。其实就是指重构init方法在创建对象的那一瞬间能够给属性直接赋值。
import UIKit
class MyClass{
// 类中的属性 一定要进行初始化 或者 在初始器中初始化 两个地方有一个地方进行初始化就不会报错
var text : String = ""
// 可选值 默认初始化成 nil
var response : String?
// 不提供 初始化器 有一个无参的默认的 没有逐一初始化器
// 提供系统会回收默认的 一般需要我们补上
init(text : String){
self.text = text
}
}
var mc = MyClass(text : "test")
class Food{
var name : String
var count = 0
// 真正完成初始化的 叫指定构造器
// 指定构造器和 便利构造器可以有多个
init(name : String){
self.name = name
}
// 便利初始器
// 便利初始器 最终一定会调用一个指定初始器结束
convenience init(){
//name = "test"
self.init(name : "test")
}
convenience init(x :Double){
print(x)
self.init()
}
}
class Apple : Food {
var quantity : Int
// 指定初始化器
init(name: String,quantity : Int) {
// 先初始化子类属性
self.quantity = quantity
// 再调用父类的属性初始化器
super.init(name: name)
// 对父类属性重新复制 必须写在父类初始化器之后
self.name = "abc"
}
// 写一个带一个String 参数的便利初始化器
override convenience init(name: String) {
self.init(name : name, quantity : 10)
}
deinit{
print("对象销毁时自动调用")
}
}
以上是关于6.Swift协议|扩展|访问权限|异常调试|类型转换|运算函数|ARC|类类型初试化器|值类型初始化器的主要内容,如果未能解决你的问题,请参考以下文章
Swift - 协议类扩展(extension) 访问控制(fileprivate,private,internal,public,open)