1.Swift调用OC
Swift
项目创建OC
对象如下
NS_ASSUME_NONNULL_BEGIN
int sum(int a, int b);
@interface Person : NSObject
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *name;
- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name;
+ (instancetype)personWithAge:(NSInteger)age name:(NSString *)name;
- (void)run;
+ (void)run;
- (void)eat:(NSString *)food other:(NSString *)other;
+ (void)eat:(NSString *)food other:(NSString *)other;
@end
int sum(int a, int b){
return a + b;
}
@implementation Person
- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name{
self = [super init];
if (self) {
_name = name;
_age = age;
}
return self;
}
+ (instancetype)personWithAge:(NSInteger)age name:(NSString *)name{
return nil;
}
+ (void)run{
NSLog(@"Person +run");
}
- (void)run{
NSLog(@"Person -run %@, %@",@(_age), _name);
}
+ (void)eat:(NSString *)food other:(NSString *)other{
NSLog(@"Person +eat %@ %@",food, other);
}
- (void)eat:(NSString *)food other:(NSString *)other{
NSLog(@"Person -eat %@ %@ %@ %@",@(_age), _name,food, other);
}
@end
一般都会自动创建一个Target-Bridging-Header.h
的桥接文件,比如在Swift
工程里面,需要调用OC
的类,在桥接文件里面写上#import "Person.h"
即可调用。
1.1 基本使用
var str: String = "Kejing"
// Swift
var p = Person(age: 20, name: str);
print(p.name, p.age)
p.run()
p.eat("吃饭", other: "吃肉")
Person.run()
Person.eat("不吃", other: "Kj")
print(sum(20, 30))
1.2 C函数冲突
func sum(_ a: Int, _ b: Int) -> Int {
a - b
}
print(sum(20, 30))
我们在swift
中的有个同名的方法,就会覆盖import
进来的C函数。
func sum(_ a: Int, _ b: Int) -> Int {
a - b
}
@_silgen_name("sum")
func swift_sum(_ v1: Int32, _ v2: Int32) -> Int32
print(swift_sum(20, 30))
print(sum(20, 30))
可以用_silgen_name
的方式进行重命名,那么调用原来的swift
函数就可以不变,调用import
进来的C
函数就可以用重命名的方式调用。
@_silgen_name
后面跟的参数只要这个C/C++函数存在,就可以重命名,比如系统分配内存的私有方法swift_allocObject
,理论上也可以采用这种方式重命名,然后就可以调用系统级别的私有方法了。
2. OC调用Swift
Xcode已经默认生成了一个OC调用Swift的头文件,格式targetname-Swift.h
根据上面Swift调用OC的代码,都介绍了,新增一个C方法testMethod
给Swift调用,然后OC里面再调用Swift的Car类
import Foundation
@objcMembers class Car: NSObject {
var price: Double
var brand: String
init(price: Double, brand: String) {
self.price = price
self.brand = brand
}
func run() -> Void {
print(price, brand, "run")
}
static func run() {
print("Car run")
}
}
extension Car {
func test() {
print(price, brand, "test")
}
}
Swift
暴露给OC
的类必须继承子NSObject
- 使用
@objc
修饰需要暴露给OC
的成员- 使用
@objcMembers
修饰类,代表所有成员都会暴露给OC,包括扩展
标记好之后,Person.m
类中,导入头文件#import "TestSwift-Swift.h"
,然后看下头文件生成的Car
类
SWIFT_CLASS("_TtC9TestSwift3Car")
@interface Car : NSObject
@property (nonatomic) double price;
@property (nonatomic, copy) NSString * _Nonnull brand;
- (nonnull instancetype)initWithPrice:(double)price brand:(NSString * _Nonnull)brand OBJC_DESIGNATED_INITIALIZER;
- (void)run;
+ (void)run;
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable");
@end
@interface Car (SWIFT_EXTENSION(TestSwift))
- (void)test;
@end
在OC的类中调用代码如下
void testMethod(){
Car *car = [[Car alloc] initWithPrice:42 brand:@"BMW"];
[car run];
[car test];
[Car run];
}
3.灵魂拷问
1. 为什么Swift暴露给OC的类最终要继承自NSObject
Car *car = [[Car alloc] initWithPrice:42 brand:@"BMW"];
因为调用都是需要alloc
,这个方法就是NSObject
才有的,而且方法都是走objc_msgSend
的,因此,都必须继承自NSObject
2. OC暴露给Swift调用底层走的是什么?
从某方面来理解,OC写的类,无论自己调用还是给Swift调都是走Runtime
那一套,.m
文件编译的时候就决定了,另一方面,看下汇编就知道了
3. 暴露给OC调用的Swift类自己调用底层走的什么?
上面可以看到,暴露给OC调用的的Swift类,在OC类调用都是alloc
无用质疑都是走runtime
那一套,但是虽然暴露给OC了,继承自NSObject
,如果调用还是用Swift的调用方式,这种方式底层走的就是默认的虚表方式。
4. String使用
4.1 插入和删除
var emptyStr1 = ""
var emptyStr2 = String()
var str = "123456" print(str.hasPrefix("123")) // true print(str.hasSuffix("456")) // true
var str: String = "1" // 拼接,jack_rose str.append("_2")
// 重载运算符 +
str = str + "_3" // 重载运算符 += str += "_4"
// \()插值
str = "\(str)_5"
// 长度,9,1_2_3_4_5 print(str.count)
var str = "1_2"
// 1_2_
str.insert("_", at: str.endIndex)
// 1_2_3_4
str.insert(contentsOf: "3_4", at: str.endIndex)
// 1666_2_3_4
str.insert(contentsOf: "666", at: str.index(after: str.startIndex))
// 1666_2_3_8884
str.insert(contentsOf: "888", at: str.index(before: str.endIndex))
// 1666hello_2_3_8884
str.insert(contentsOf: "hello", at: str.index(str.startIndex, offsetBy: 4))
// 666hello_2_3_8884
str.remove(at: str.firstIndex(of: "1")!)
// hello_2_3_8884
str.removeAll {
$0 == "6" }
var range = str.index(str.endIndex, offsetBy: -4)..<str.index(before: str.endIndex) // hello_2_3_4
str.removeSubrange(range)
4.2 SubString
var str = "1_2_3_4_5"
// 1_2
var substr1 = str.prefix(3)
// 4_5
var substr2 = str.suffix(3)
// 1_2
var range = str.startIndex..<str.index(str.startIndex, offsetBy: 3) var substr3 = str[range]
// 最初的String,1_2_3_4_5 print(substr3.base)
// Substring -> String
var str2 = String(substr3)
Substring和它的base,共享字符串数据
Substring发生修改 或者 转为String时,会分配新的内存存储字符串数据
4.3 String 和 NString
var str1: String = "jack"
var str2: NSString = "rose"
var str3 = str1 as NSString
var str4 = str2 as String
// ja
var str5 = str3.substring(with: NSRange(location: 0, length: 2)) print(str5)
String
和NSString
可以随时桥接转换,如果觉得哪边的API不好用,可以转过去用
5. 多线程
5.1 异步
public typealias Task = () -> Void
public func async(_ task: @escaping Task) {
_async(task)
}
public func async(_ task: @escaping Task, _ mainTask: @escaping Task){
_async(task, mainTask)
}
private func _async(_ task: @escaping Task, _ mainTask: Task? = nil){
let workTask = DispatchWorkItem(block: task)
DispatchQueue.global().async(execute: workTask)
if let main = mainTask {
workTask.notify(queue: DispatchQueue.main, execute: main)
}
}
5.2 延迟
public typealias Task = () -> Void
@discardableResult
public func asyncDelay(_ seconds: Double,
_ task: @escaping Task) -> DispatchWorkItem {
return _asyncDelay(seconds, task)
}
@discardableResult
public func asyncDelay(_ seconds: Double,
_ task: @escaping Task,
_ mainTask: @escaping Task) -> DispatchWorkItem {
return _asyncDelay(seconds, task, mainTask)
}
private func _asyncDelay(_ seconds: Double,
_ task: @escaping Task,
_ mainTask: Task? = nil) -> DispatchWorkItem {
let item = DispatchWorkItem(block: task)
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + seconds, execute: item)
if let main = mainTask {
item.notify(queue: DispatchQueue.main, execute: main)
}
return item
}
5.3 Once
dispatch_once
已经被swift中废物,可以用 类型静态属性
或者全局常量变量代替
,默认断点bt
都是lazy + dispatch_once
的效果
fileprivate let initTask1: Void = {
print("init task1")
}()
class Person{
static let initTask2: Void = {
print("init task2")
}()
static func test() -> Void {
Self.initTask2
}
}
5.4 加锁
class Cache {
private static var data = [String: Any]()
private static var lock = DispatchSemaphore(value: 1)
static func set(_ key: String, _ value: Any) {
lock.wait()
defer {
lock.signal() }
data[key] = value
}
}
// Foundation
private static var lock = NSLock()
static func set(_ key: String, _ value: Any) {
lock.lock()
defer {
lock.unlock() }
}
private static var lock = NSRecursiveLock()
static func set(_ key: String, _ value: Any) {
lock.lock()
defer {
lock.unlock() }
}
6. Array使用
6.1 Map
,Filter
,Reduce
// map
var arr = [1,2,3,4]
//var arr2 = arr.map { (element) -> Int in
// element * 2
//}
var arr2 = arr.map {
$0 * 2 }
// [2, 4, 6, 8]
print(arr2)
// filter
//var arr3 = arr.filter { (element) -> Bool in
// element % 2 == 0
//}
var arr3 = arr.filter {
$0 % 2 == 0 }
print(arr3)
// reduce
//var arr4 = arr.reduce(10) { (relust, element) -> Int in
// return relust + element
//}
var arr4 = arr.reduce(10) {
$0 + $1 }
print(arr4)
首先这边的$0
代表的是闭包函数的参数,同理$1
就是第二个参数,Map
就是遍历数组,映射成新的数组,Filter
就是根据返回值过滤,Reduce
中有两个参数,第一个参数就是上一个结果的值,第二个就是遍历出来的值,而且有个初始化值。下面用Recude
实现map
和filter
// map
var arr = [1,2,3,4]
print(arr.map{
$0*2 })
//public func reduce<Result>(_ initialResult: Result,
// _ nextPartialResult: (Result, Element) -> Result)
// -> Result
print(arr.reduce([]) {
(result, element) -> Array<Int> in
result + [ 2 * element ]
})
print(arr.reduce([], {
$0 + [ 2*$1 ] }))
// filter
print(arr.filter {
$0%2 == 0 })
print(arr.reduce([]) {
(result, element) -> Array<Int> in
element % 2 == 0 ? result + [element] : result
})
print(arr.reduce([]) {
$1 % 2 == 0 ? $0 + [$1] : $0 })
6.2 flatMap
,compactMap
var arr = [1,2,3,4]
var arr1 = arr.map {
Array.init(repeating: $0, count: $0) }
var arr2 = arr.flatMap {
Array.init(repeating: $0, count: $0) }
// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
print(arr1)
// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
print(arr2)
var arr3 = ["123", "test", "mikejing", "-3213"]
// [Optional(123), nil, nil, Optional(-3213)]
var arr4 = arr3.map {
Int($0) }
print(arr4)
// [123, -3213]
var arr5 = arr3.compactMap{
Int($0) }
print(arr5)
6.3 lazy
优化
正常的map
会在调用之前就遍历一遍
var arr = [1,2,3,4]
let resut = arr.lazy.map {
(element) -> Int in
print("map\(element)")
return element * 2
}
print("start----")
print("mapped", resut[0])
print("mapped", resut[1])
print("mapped", resut[2])
print("end----")
//start----
//map1
//mapped 2
//map2
//mapped 4
//map3
//mapped 6
//end----
6.4 Optional
的map
和flatMap
var num1: Optional<Int> = .some(10)
// Optional(20)
var num2 = num1.map{
$0 * 2 }
var num3: Int? = nil
// nil
var num4 = num3.map{
$0 * 2 }
var num5: Int? = 10
var num6 = num5.map{
Optional.some($0 * 2) }
var num7 = num5.flatMap{
Optional.some($0 * 2) }
// Optional(Optional(20))
print(num6)
// Optional(20)
print(num7)
有了map
在可选项中,以下是等价的
var num1: Optional<Int> = .some(10)
// Optional(20)
var num2 = num1.map{
$0 * 2 }
// Optional(20)
var num3 = (num1 != nil) ? (num1! * 2) : nil
可以看到,之前用let num
的方式进行可选项绑定,现在也可以用map
,更加的优雅,而且flatMap
是可以消除多个可选项嵌套的。
// 案例一
var fmt1 = DateFormatter()
fmt1.dateFormat = "yyyy-MM-ddd"
var str: String? = "2021-11-02"
// old
var date1 = str != nil ? fmt1.date(from: str!) : nil
// new
print(str.flatMap{
fmt1.date(from: $0) })
// 案例二
var score: Int? = 90
var str1 = score != nil ? "Score \(score)" : "No Score"
var str2 = score.map{
"score \($0)" } ?? "No Score"
对可选项做
map
,如果不是空,会自动解包,如果是nil,直接返回
实际案例一
struct Person {
var name: String
var age: Int
}
var items = [
Person(name: "qishu", age: 3),
Person(name: "jiaojiao", age: 28),
Person(name: "kejing", age: 30)
]
func getPerson1(_ name: String) -> Person? {
let index = items.firstIndex {
$0.name == name }
return index != nil ? items[index!] : nil
}
func getPerson2(_ name: String) -> Person? {
items.firstIndex {
$0.name == name }.map {
items[$0] }
}
实际案例二
struct Person {
var name: String
var age: Int
init?(_ json: [String : Any]) {
guard let name = json["name"] as? String,
let age = json["age"] as? Int else{
return nil
}
self.name = name
self.age = age
}
}
var json: Dictionary? = ["name": "珂璟", "age":30]
// Optional(TestSwift.Person(name: "珂璟", age: 30))
var p1 = json != nil ? Person(json!) : nil
// Optional(TestSwift.Person(name: "珂璟", age: 30))
var p2 = json.flatMap {
Person($0) }
if let p = p2{
print(p.name, p.age)
}else{
print("不存在")
}
转载:https://blog.csdn.net/Deft_MKJing/article/details/116403111