0%

Swift 创建链表(Linked List)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 定义节点
public class LinkedListNode<T> {
var value: T

// 前一个节点
weak var pervious: LinkedListNode?

// 下一个节点
var next: LinkedListNode?

// 初始化节点
public init(value: T) {
self.value = value
}
}
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
public class LinkedList<T> {
public typealias Node = LinkedListNode<T>

// 指向第一个节点的指针 私有
private var head: Node?

// 是否为空
public var isEmpty: Bool {
return head == nil
}

// 节点总数
public var count: Int {
guard var node = head else {
return 0
}

var count = 1
while let next = node.next {
node = next
count += 1
}
return count
}

// 指向第一个节点的指针 公共
public var first: Node? {
return head
}

// 指向最后的节点的指针
public var last: Node? {
guard var node = head else {
return nil
}

// 直到 node.next 为nil
while let next = node.next {
node = next
}
return node
}

// 得到index 的 node
public func node(atIndex index: Int) -> Node? {
guard index != 0 else {
return head!
}

var node = head!.next
guard index < count else {
return nil
}

for _ in 1 ..< index {
node = node?.next
if node == nil {
break
}
}
return node!
}

/// 插入节点
// 插入到最后
public func appendToTail(value: T) {
let newNode = Node(value: value)

// 更新最后一个节点,newNode成为最后一个节点
// 前一个节点成为成为倒数第二个节点
if let lastNode = last {
newNode.pervious = lastNode
lastNode.next = newNode
} else {
// 空白链表直接插入
head = newNode
}
}

// 插入到最前
public func insertToHead(value: T) {
let newHead = Node(value: value)
if head == nil {
// 空链表直接插入
head = newHead
} else {
newHead.next = head
head?.pervious = newHead
head = newHead
}

}

// 插入到特定的索引位置
public func insert(_ node: Node, atIndex index: Int) {
if index < 0 {
print("invalid input index")
return
}

let newNode = node

if count == 0 {
head = newNode
} else {
if index == 0 {
newNode.next = head
head?.pervious = newNode
head = newNode
} else {
if index > count {
print("out of range")
return
}

let prev = self.node(atIndex: index - 1)
let next = prev?.next

newNode.pervious = prev
newNode.next = prev?.next
prev?.next = newNode
next?.pervious = newNode
}
}
}

/// 移除节点
// 移除所有节点
public func removeAll(){
head = nil
}

// 移除最后一个节点
public func removeLast() -> T? {
guard !isEmpty else {
return nil
}
return remove(node: last!)
}

// 通过引用移除节点
public func remove(node: Node) -> T? {
guard head != nil else {
print("Linked List is empty")
return nil
}

let prev = node.pervious
let next = node.next

if let prev = prev {
prev.next = next
} else {
head = next
}

next?.pervious = prev

node.pervious = nil
node.next = nil
return node.value
}

// 通过index移除节点
public func removeAt(_ index: Int) -> T? {
guard head != nil else {
print("Linked List is empty")
return nil
}

let node = self.node(atIndex: index)
guard node == nil else {
return nil
}
return remove(node: node!)
}

// 打印所有节点
public func printAllNodes() {
guard head != nil else {
print("Linked List is empty")
return
}

var node = head
print("\nsatart printing all nodes:")
for index in 0 ..< count {
if node == nil {
break
}
print("[\(index)]\(node!.value)")
node = node!.next
}
}
}

使用链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let list = LinkedList<String>()

list.isEmpty
list.first
list.count

list.appendToTail(value: "Swift")
list.isEmpty
list.first!.value
list.count
list.last!.value

list.appendToTail(value: "Java")
list.first!.value
list.last!.value

list.insert(LinkedListNode.init(value: "C++"), atIndex: 2)

list.printAllNodes()

Swift 创建队列(queue)

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
/// 队列 queue
// 用数组来实现队列内部的线性表

public struct Queue<T> {
fileprivate var queueArray = [T]()

public var count: Int {
return queueArray.count
}

public var isEmpty: Bool {
return queueArray.isEmpty
}

// 前面的元素
public var front: T? {
if isEmpty {
print("queue is empty")
return nil
} else {
return queueArray.first
}
}

// 添加元素
public mutating func enqueue(_ element: T) {
queueArray.append(element)
}

// 移除元素
public mutating func dequeue() -> T? {
if isEmpty {
print("queue is empty")
return nil
} else {
return queueArray.removeFirst()
}
}

// 打印元素
public mutating func printAllElements() {
guard count > 0 else {
print("queue is empty")
return
}

print("\nprint all queue elements:")
for (index, value) in queueArray.enumerated() {
print("[\(index)]\(value)")
}
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
// 使用队列
var queue = Queue.init(queueArray: [])
queue.isEmpty
queue.printAllElements()
queue.count

queue.enqueue("abc")
queue.printAllElements()

queue.enqueue("xyz")
queue.printAllElements()

queue.front

在用delegate回调数据时,避免避免持续调用 [_delegate respondsToSelector:@selector(someThingFunction)

GCNetworkFetcher.h

定义protocol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import <Foundation/Foundation.h>
@class GCNetworkFetcher;

@protocol GCNetworkFetcherDelegate <NSObject>

@optional
- (void)networkFetcher:(GCNetworkFetcher *)fetcher didReceiveData:(NSData *)data;
- (void)networkFetcher:(GCNetworkFetcher *)fetcher didFaileWithError:(NSError *)error;
- (void)networkFetcher:(GCNetworkFetcher *)fetcher didUpdateProgressTo:(float)progress;

@end

@interface GCNetworkFetcher : NSObject

@property (nonatomic, weak) id<GCNetworkFetcherDelegate>delegate;

@end

GCNetworkFetcher.m

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
#import "GCNetworkFetcher.h"

@interface GCNetworkFetcher () {
//用位段的数据类型缓存方法的响应能力,避免每次回调数据的时候都去检测一下 避免持续调用 if( [_delegate respondsToSelector:@selector(networkFetcher:didUpdateProgressTo:)]) {}
//用结构体来缓存委托对象是否能响应特定的选择器
struct {
unsigned int didReceivedData : 1;
unsigned int didFaileWithError : 1;
unsigned int didUpdateProgressTo : 1;
}_delegateFlags;
}

@end

@implementation GCNetworkFetcher

// 实现缓存功能所有的代码可以写在delegate属性所对应的设置方法里
- (void)setDelegate:(id<GCNetworkFetcherDelegate>)delegate {
_delegate = delegate;
_delegateFlags.didReceivedData = [delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)];
_delegateFlags.didFaileWithError = [delegate respondsToSelector:@selector(networkFetcher:didFaileWithError:)];
_delegateFlags.didUpdateProgressTo = [delegate respondsToSelector:@selector(networkFetcher:didUpdateProgressTo:)];
}

- (void)getData:(NSData *)data {
if (_delegateFlags.didReceivedData) {
[_delegate networkFetcher:self didReceiveData:data];
}
}

- (void)setError:(NSError *)error {
if (_delegateFlags.didFaileWithError) {
[_delegate networkFetcher:self didFaileWithError:error];
}
}

- (void)progress:(float)progress {
if (_delegateFlags.didUpdateProgressTo) {
[_delegate networkFetcher:self didUpdateProgressTo:progress];
}
}

理解objc_msgSend的作用

1
objc_msgSend(void /* id self, SEL op, ... */ )

是一个参数可变的函数,能接受两个或者两个以上的参数,会根据依次的接受者与选择器的类型来调用适当的方法,为了完成此操作,该方法需要在接受者所属的类中寻找其 方法列表,如果找到与选择器相同的方法就调至其实现代码,若找不到沿着继承体系向上查找,等找到合适的方法之后在跳转,如果最终找不到,就执行消息转发;

objc_msgSend函数举例

被调方法类

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
// GCMsgSend.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

struct myStructTest {
char *name;
int age;
};

@interface GCMsgSend : NSObject

- (void)noArgumentAndNoReturnValue;

- (void)hasArguments:(NSString *)arg;

- (NSString *)noArgumentsButRetuenValue;

- (int)hasArguments:(NSString *)arg andReturnValue:(int)arg1;

int cStyleFunc(const void *arg1, const void *arg2);

- (float)noArgumentAndReturnFloatValue;

- (struct myStructTest)returnStructValue;

@end


@interface GCMsgSendClass: GCMsgSend

- (void)getSuperClass;

@end
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
// GCMsgSend.m
#import "GCMsgSend.h"

@implementation GCMsgSend

- (void)noArgumentAndNoReturnValue {
NSLog(@"%s was called, and it has no arguments and return value", __FUNCTION__);
}

- (void)hasArguments:(NSString *)arg {
NSLog(@"%s was called, and arguments is %@", __FUNCTION__, arg);
}

- (NSString *)noArgumentsButRetuenValue {
NSLog(@"%s was called, and return value is %@", __FUNCTION__, @"不带参数,但是有返回值");
return @"不带参数,但是有返回值";
}

- (int)hasArguments:(NSString *)arg andReturnValue:(int)arg1 {
NSLog(@"%s was called, and argument is %@, retuen value is %d", __FUNCTION__, arg, arg1);
return arg1;
}

//声明一个C函数
int cStyleFunc(const void *arg1, const void *arg2) {
NSLog(@"%s was called, arg1 is %s, and age2 is %s", __FUNCTION__, arg1, arg2);
return 1;
}

- (float)noArgumentAndReturnFloatValue {
NSLog(@"%s was called, 带浮点数的返回值", __FUNCTION__);
return 10.24;
}

- (struct myStructTest)returnStructValue {
struct myStructTest test = {
"Ghost",
1024,
};
return test;
}
@end


@implementation GCMsgSendClass

- (void)getSuperClass {

}

@end

掉用类

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
#import "GCMsgSend.h"
#import <objc/message.h>

- (void)msgTest {
//创建对象
GCMsgSend *msg = ( (GCMsgSend * (*)(id, SEL)) objc_msgSend) ((id)[GCMsgSend class],@selector(alloc));

//初始化对象
msg = ((GCMsgSend *(*)(id, SEL))objc_msgSend) ((id)msg, @selector(init));

//调用无参无返回值的方法
((void (*)(id, SEL))objc_msgSend)((id)msg, @selector(noArgumentAndNoReturnValue));

//带参数不带无返回值
((void(*)(id, SEL, NSString *))objc_msgSend)((id)msg, @selector(hasArguments:), @"一个参数,无返回值");

//不带参数有返回值
NSString *retValue = ((NSString *(*)(id, SEL))objc_msgSend)((id)msg, @selector(noArgumentsButRetuenValue));
NSLog(@"返回值是: %@", retValue);

//带参数带返回值
int returnValue = ((int (*)(id, SEL, NSString *, int))objc_msgSend)((id)msg, @selector(hasArguments:andReturnValue:), @"参数1", 2018);
NSLog(@"返回值是: %d", returnValue);

//动态添加方法再调用
class_addMethod(msg.class, NSSelectorFromString(@"cStyleFunc"), (IMP)cStyleFunc, "v@:");
returnValue = ((int(*)(id, SEL, const void *, const void *))objc_msgSend)((id)msg, NSSelectorFromString(@"cStyleFunc"), "参数1", "参数2");
NSLog(@"返回值是: %d", returnValue);

//带浮点返回值
float returnFloatValue = ((float(*)(id, SEL))objc_msgSend)((id)msg, @selector(noArgumentAndReturnFloatValue));
NSLog(@"浮点数返回值是: %f", returnFloatValue);

//带结构体的返回值 objc_msgSend_stret 已经废弃
struct myStructTest structValue = ((struct myStructTest(*)(id, SEL))objc_msgSend)((id)msg, @selector(returnStructValue));
NSLog(@"结构体返回: name = %s, age = %d", structValue.name, structValue.age);

//给父类发送消息
//初始化子类
GCMsgSendClass *msgClass = ((GCMsgSendClass *(*)(id, SEL))objc_msgSend)((id)[GCMsgSendClass class], @selector(alloc));
msgClass = ((GCMsgSendClass *(*)(id, SEL))objc_msgSend)((id)msgClass, @selector(init));
//给父类的方法发送消息 掉用objc_msgSendSuper 会Crash
((void(*)(id, SEL, NSString *))objc_msgSend)((id)msgClass, @selector(hasArguments:), @"子类调用父类的方法");
}

理解消息转发机制分为两大阶段:

第一阶段:

先征询接受者所属的类, 看其是否能动态添加方法,以处理当前这个‘未知的选择器’,这个叫做‘动态方法解析’

第二阶段:

涉及‘完整的消息转发机制’, 如果运行期系统已经把第一阶段执行完,那么接受者就无法再以动态新增的方法的手段来响应包含该选择器的消息了,此时,运行期系统会请求接受者以其他手段来处理与消息有关的方法调用,

这个细节分为两步,首先请接受者看看有没有其他对象能处理这条消息,
  1. 若有,则运行期系统会把消息转给那个对象,消息转发结束,一切如常;
  2. 若没有,则穷完整的消息转发机制,运行期系统会把消息有关的全部细节都封装到NSInvocation对象中,再给接受者最后一个机会,令其设法解决当前还未处理的这条消息;

// 创建GCMessageForwarding,在 GCMessageForwarding.h写一个放方法但是不去实现```
-(void)lowercasseString;

1
2
3

在外部调用时: 就会发生Crash

方法没实现,由NSobject的doesNotRecognizeSelector抛出, 此异常表明:接受者的类型是GCMessageForwarding,而该接受者无法理解该选择器
-[GCMessageForwarding lowercasseString]: unrecognized selector sent to instance 0x1740044d0
*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[GCMessageForwarding lowercasseString]: unrecognized selector sent to instance 0x1740044d0’

1
2

##### GCMessageForwarding.m里面实现

void messageForwarding() {
NSLog(@”show Test02”);
}

  • (BOOL)resolveInstanceMethod:(SEL)sel {
    NSString *selString = NSStringFromSelector(sel);
    if ([selString isEqualToString:@”lowercasseString”]) {
      class_addMethod(self, sel, (IMP)messageForwarding, "v@:@");
    }
    return YES;
    }
    这时就会打印 ```show Test02```
    

方法 resolveInstanceMethod 也没实现

如果方法 resolveInstanceMethod 也没实现,就会掉用备用方法 forwardingTargetForSelector,把这条消息转给其他接受者来处理

整个调用流程

lowercasseString(未实现) -> resolveInstanceMethod(未实现) ->forwardingTargetForSelector(未实现) -> resolveInstanceMethod(未实现) -> NSobject的doesNotRecognizeSelector抛出异常