Swift tips 笔记

Swift tips 笔记

  • CaseIterable协议

enum遵守了CaseIterable协议可以实现遍历枚举值

enum Season : CaseIterable {
    case spring, summer, autumn, winter
}
print(Season.allCases.count)
Season.allCases.forEach { (s) in
    print(s)
}
  • defer 语句

defer 用来定义离开代码块前必须执行的代码

  • assert 断言

断言机制:不符合指定条件就抛出运行时错误,常用于调试Debug阶段的条件编译。
默认情况下Swift的断言只会在Debug模式下生效,Release模式下会失效。
修改断言机制的行为:

-assert-config Release: 强制关闭断言
-assert-config Debug: 强制开启断言
  • 指针

Swift中的指针被定义为不安全的。

UnsafePointer<Int> 类似于 const int *
UnsafeMutablePointer<Int> 类似于 int *
UnsafeRawPointer 类似于 const void *
UnsafeMutableRawPointer 类似于 void *

Demo:
var number = 0
test(&number)
print("number = \(number)")
    
test1(&number)
    
test2(&number)
print("number = \(number)")
test3(&number)
func test(_ ptr: UnsafeMutablePointer<Int>) {
    ptr.pointee += 10
}

func test1(_ ptr: UnsafePointer<Int>) {
    print(ptr.pointee)
}
    
func test2(_ ptr: UnsafeMutableRawPointer) {
    // 修改数据
    ptr.storeBytes(of: 30, as: Int.self)
}
    
func test3(_ ptr: UnsafeMutableRawPointer) {
    // 读取数据
    print(ptr.load(as: Int.self))
}

1、获取指向某个变量的指针

// 通过变量 获取 UnsafePointer 类型的指针
var ptr = withUnsafePointer(to: &number) { $0 }
// 通过变量 获取 UnsafeMutablePointer 类型的指针
var ptr1 = withUnsafeMutablePointer(to: &number) { $0 }
// 通过变量 获取 UnsafeMutableRawPointer 类型的指针
var ptr2 = withUnsafeMutablePointer(to: &number, { UnsafeMutableRawPointer($0)})
// 通过变量 获取 UnsafeRawPointer 类型的指针
var ptr3 = withUnsafePointer(to: &number, {UnsafeRawPointer($0)})

2、获取指向堆空间实例的指针

class Person {}
var p = Person()
// ptr 指向 p 相当于存放的是 变量p的内存地址
var ptr = withUnsafePointer(to: &p, { UnsafeRawPointer($0) })
print(ptr)
// addressPtr 读取8个字节 相当于就是p存储的地址,即Person()在堆中的地址
let addressPtr = ptr.load(as: Int.self)
// 用addressPtr初始化一个地址,相当于helpPtr指向堆空间的地址
var helpPtr = UnsafeRawPointer(bitPattern: addressPtr)
print(helpPtr)

3、创建指针

方式一:
var ptr = malloc(16)
// 向前8个字节存入数据
ptr?.storeBytes(of: 10, as: Int.self)
ptr?.storeBytes(of: 20, toByteOffset: 8, as: Int.self)
print(ptr?.load(as: Int.self))
print(ptr?.load(fromByteOffset: 8, as: Int.self))
free(ptr)

方式二:
var ptr2 = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
// 向前8个字节存入数据
ptr2.storeBytes(of: 23, as: Int.self)
// 先偏移8个字节然后存入数据
ptr2.advanced(by: 8).storeBytes(of: 44, as: Int.self)
print(ptr2.load(as: Int.self))
print(ptr2.advanced(by: 8).load(as: Int.self))
ptr2.deallocate()

方式三:
var ptr = UnsafeMutablePointer<Int>.allocate(capacity: 3)
ptr.initialize(to: 11)
ptr.successor().initialize(to: 22)
ptr.successor().successor().initialize(to: 33)
print(ptr.pointee) // 11
print((ptr + 1).pointee) // 22
print((ptr + 2).pointee) // 33
print(ptr[0]) // 11
print(ptr[1]) // 22
print(ptr[2]) // 33
ptr.deinitialize(count: 3)
ptr.deallocate()

方式四:
class Person {
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    deinit { print(name, "deinit") } }
var ptr = UnsafeMutablePointer<Person>.allocate(capacity: 3)
ptr.initialize(to: Person(age: 10, name: "Jack"))
(ptr + 1).initialize(to: Person(age: 11, name: "Rose"))
(ptr + 2).initialize(to: Person(age: 12, name: "Kate"))
// 反初始化
ptr.deinitialize(count: 3)
ptr.deallocate()

4、指针之间的转换

unsafeBitCast是忽略数据类型的强制转换,不会因为数据类型的变化而改变原来的内存数据 p 类似于C++中的reinterpret_cast

var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
ptr.assumingMemoryBound(to: Int.self).pointee = 11
(ptr + 8).assumingMemoryBound(to: Double.self).pointee = 22.0
print(unsafeBitCast(ptr, to: UnsafePointer<Int>.self).pointee) // 11
print(unsafeBitCast(ptr + 8, to: UnsafePointer<Double>.self).pointee)
ptr.deallocate()
  • 代码标记
// MARK: 类似于OC中的 #pragma mark
// MARK: - 类似于OC中的 #pragma mark - n
// TODO: 用于标记未完成的任务
// FIXME: 用于标记待修复的问题
  • 条件编译
// 操作系统:macOS\iOS\tvOS\watchOS\Linux\Android\Windows\FreeBSD
#if os(macOS) || os(iOS)
// CPU架构:i386\x86_64\arm\arm64
#elseif arch(x86_64) || arch(arm64)
// swift版本
#elseif swift(<5) && swift(>=3)
// 模拟器
#elseif targetEnvironment(simulator) // 可以导入某模块
#elseif canImport(Foundation)
#else
#endif

在这里插入图片描述

#if DEBUG
    print("debug")
#else
    print("release")
#endif
    
#if OTHER
    print("debug")
#else
    print("release")
#endif

定义Debug打印方法

func log<T>(_ msg: T,
            file: NSString = #file,
            line: Int = #line,
            fn: String = #function) {
    #if DEBUG
    let prefix = "\(file.lastPathComponent)_\(line)_\(fn):" print(prefix, msg)
    #endif
}
  • 系统版本检测
if #available(iOS 10, macOS 10.12, *) {
    // 对于iOS平台,只在iOS10及以上版本执行
    // 对于macOS平台,只在macOS 10.12及以上版本执行
    // 最后的*表示在其他所有平台都执行
}
  • API可用性

苹果官方说明

  • OC和Swift之间的相互调用

1、Swift暴露给OC的类最终继承自NSObject
2、使用@objc修饰需要暴露给OC的成员
3、通过@objc重命名Swift暴露给OC的符号(类名、属性名、函数名)
4、使用@objcMembers修饰类
代表默认所有都会暴露给OC
最终是否成功暴露,还需要考虑成员自身的访问级别
5、被@objc dynamic 修饰的内容会具有动态性,调用方法会走runtime流程

  • 协议

1、利用协议实现前缀效果

// 定义前缀结构体
struct MJ<Base> {
    let base: Base
    init(_ base: Base) {
        self.base = base
    }
}

// 定义协议,扩展实现默认的前缀
protocol MJCompatible {}
extension MJCompatible {
    var mj: MJ<Self> {
        set {}
        get {
            MJ(self)
        }
    }
    static var mj: MJ<Self>.Type {
        set {}
        get {
            MJ<Self>.self
        }
    }
}

// 对应的类实现协议,扩展特定的方法
extension String: MJCompatible {}
extension MJ where Base == String {
    func numberCount() -> Int {
        return 5
    }
}

2、Base: 类

class Person {}
class Student: Person {}
// 给Person扩展mj前缀
extension Person: MJCompatible {}
// 给Person类型 添加扩展test方法
extension MJ where Base: Person {
    func test() {
        print("test")
    }
}

let s = Student()
s.mj.test()
let p = Person()
p.mj.test()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值