斗扣年华

与扣斗,其乐无穷


  • Home

  • Archives

debug技巧

Posted on 2020-09-28 | Edited on 2020-09-29

deubg context

断点停在Objective-C代码,LLDB使用Objective-C上下文。

断点停在Swift代码,LLDB使用Swift上下文。

强制表达式使用OC上下文

1
2
3
// -l 使用的语言
// -O -- 等同po
(lldb) expression -l objc -O -- [UIApplication sharedApplication]

User defined variables

当你打印对象时LLDB会自动创建临时变量,你也可以自己创建变量。

比如有时想自建一个对象再去实验一些方法

1
2
3
(lldb) po id test = [NSObject new]
(lldb) po test
error: use of undeclared identifier 'test'

这样会有报错

你得使用$标记告诉LLDB你想记住的变量

1
2
3
(lldb) po id $test = [NSObject new]
(lldb) po $test
<NSObject: 0x60000001d190>

xcode 11.3.1

符号断点:MasterContainerViewController.viewDidLoad 即有效

1
(lldb) p self

LLDB会创建变量$R0

continue后再手动暂停

此时$R0还持有引用

// 看看对引用计数的影响

1
2
3
4
5
6

(lldb) expression -l swift -- $R0.title
(String?) $R6 = "Quarterback" // 这里R后面的数字不是固定的
(lldb) expression -l swift -- $R0.title = "💩💩💩💩💩"
// command + ctrl + space 搜索poop
// 控制器的标题变成了一堆便便

我们还可以这样,创建一个断点,执行那个被持有变量的方法,命中断点

可以给方法不同输入观察其输出。TDD

1
2
// -i disable this option ->  by default, LLDB will ignore any breakpoints when executing commands
(lldb) expression -l swift -O -i 0 -- $R0.viewDidLoad()

Type formatting

GDB format

The full list of output formats is as follows (taken from https://sourceware.org/gdb/ onlinedocs/gdb/Output-Formats.html):

• x: hexadecimal

• d: decimal

• u: unsigned decimal

• o: octal

• t: binary

• a: address

• c: character constant

• f: float

• s: string

LLDB’s extra formatters

LLDB’s formatters can be used like this:

(lldb) expression -f Y – 1430672467

This gives you the following output:

1
(int) $0 = 53 54 46 55             STFU

This explains the FourCC code from earlier!
LLDB has the following formatters (taken from http://lldb.llvm.org/varformats.html): • B: boolean
• b: binary
• y: bytes
• Y: bytes with ASCII
• c: character
• C: printable character
• F: complex float
• s: c-string
• i: decimal
• E: enumeration
• x: hex
• f: float
• o: octal
• O: OSType
• U: unicode16
• u: unsigned decimal
• p: pointer

1
2
3
4
// -n 告诉LLDB查询符号与函数名
(lldb) image lookup -n "-[UIViewController viewDidLoad]"
(lldb) image lookup -rn test
// Note: 使用-n来进行精确查找。rn regex search

SwiftCore

Posted on 2020-08-30

Bool

占一个字节,有效位只有一个bit

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
@frozen
public struct Bool {
@usableFromInline
internal var _value: Builtin.Int1

/// Creates an instance initialized to `false`.
///
/// Do not call this initializer directly. Instead, use the Boolean literal
/// `false` to create a new `Bool` instance.
@_transparent
public init() {
let zero: Int8 = 0
self._value = Builtin.trunc_Int8_Int1(zero._value)
}

@usableFromInline @_transparent
internal init(_ v: Builtin.Int1) { self._value = v }

/// Creates an instance equal to the given Boolean value.
///
/// - Parameter value: The Boolean value to copy.
@inlinable
public init(_ value: Bool) {
self = value
}
...

属性访问

Posted on 2020-06-05 | Edited on 2020-06-14

“对象”就是“基本构造单元”。开发者可以通过对象来存储并传递数据。

在对象之间传递数据并执行任务的过程就叫做“消息传递”

当程序裕兴起来以后,为其提供相关支持的代码叫做“Objective-C运行时环境”

它提供了一些使得对象之间能够传递消息的重要函数,并且包含创建类实例所用的全部逻辑。

属性

property 是OC一项特性,用于封装对象中的数据。

尽量描述所有关于属性相关的问题

属性访问的点语法

属性由何而来

编译器自动合成

编译器生成getter setter 实例变量

@synthesize 指定实例变量名

@dynamic 告诉编译器不要自动创建实现属性的存取方法,不会报错,相信运行时一定能找到

1.@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的

1
2
3
4
5
6
7
8
9
10
11
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
//与
@interface Person : NSObject
- (NSString *)firstName;
- (void)setFirstName:(NSString *)firstName;
- (NSString *)lastName;
- (void)setLastName:(NSString *)lastName;
@end

编译识别一样,都能通过点语法访问属性,但是后者没有实现实例变量

读写权限readonly readwrite

默认是readwrite getter setter方法都会生成

readonly 只生成getter方法

原子性访问 atomic noatomic
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

id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}

// Retain release world
id *slot = (id*) ((char*)self + offset);
if (!atomic) return *slot;

// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();

// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);
}


static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) __attribute__((always_inline));

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}

id oldValue;
id *slot = (id*) ((char*)self + offset);

if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue);
}

if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}

objc_release(oldValue);
}

void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
{
bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
bool mutableCopy = (shouldCopy == MUTABLE_COPY);
reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}

void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, true, false, false);
}

void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, false, false, false);
}


void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, true, true, false);
}

void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, false, true, false);
}

可见编译器编译代码时,通过attribute识别在属性访问方法中插入对应方法

id *slot = (id*)((char*)self + offset)

slot 二级指针存储属性地址

分析atomic

set方法中

1
2
3
4
5
6
7
8
9
10
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}

如果是atomic 会在临界区加入自旋锁

oldValue 存储旧值指针

然后赋新值

get方法中

1
2
3
4
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();

那么,atomic能保证属性访问的线程安全吗

可以看到 在setter方法中,获取新值newValue时并未加锁,当多线程写的时候,并不能保证线程安全。

换句话说,它保证的是内存管理的安全。

内存管理语义
assign
通常针对“纯量类型” 的简单赋值操作
strong

此特质表明该属性定义了一种“拥有关系”,为这种属性设置新值时,设置方法会先保留新值,释放旧值,然后再将新值设置上去

weak
unsafe_unretained
copy

方法中的self msg_send 传进来的类

ARC

RxSwift

Posted on 2020-05-30

你的答案

Posted on 2020-05-21 | Edited on 2020-06-27

0.AOP

1.copy、mutableCopy

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
// swift中的NSArray实现的copy与mutableCopy
open override func copy() -> Any {
return copy(with: nil)
}

open func copy(with zone: NSZone? = nil) -> Any {
if type(of: self) === NSArray.self {
// return self for immutable type
return self
} else if type(of: self) === NSMutableArray.self {
let array = NSArray()
array._storage = self._storage
return array
}
return NSArray(array: self.allObjects)
}

open override func mutableCopy() -> Any {
return mutableCopy(with: nil)
}

open func mutableCopy(with zone: NSZone? = nil) -> Any {
if type(of: self) === NSArray.self || type(of: self) === NSMutableArray.self {
// always create and return an NSMutableArray
let mutableArray = NSMutableArray()
mutableArray._storage = self._storage
return mutableArray
}
return NSMutableArray(array: self.allObjects)
}

可见如果属性修饰用了copy, 如果属性上声明NSArray, 即便在赋值时使用NSMutableArray, 属性新值依然得到NSArray的实例,而容器的内存也会是新开辟的。

这就是常说的浅拷贝

而copy与mutableCopy的区别仅在于新创建的容器是可变与不可变

array的这个构造方法会进行深拷贝initWithArray:<#(nonnull NSArray *)#> copyItems:<#(BOOL)#>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public convenience init(array: [Any], copyItems: Bool) {

let optionalArray : [AnyObject] =
copyItems ?
array.map { return __SwiftValue.store($0).copy() as! NSObject } :
array.map { return __SwiftValue.store($0) }

// This would have been nice, but "initializer delegation cannot be nested in another expression"
// optionalArray.withUnsafeBufferPointer { ptr in
// self.init(objects: ptr.baseAddress, count: array.count)
// }
let cnt = array.count
let buffer = UnsafeMutablePointer<AnyObject>.allocate(capacity: cnt)
buffer.initialize(from: optionalArray, count: cnt)
self.init(objects: buffer, count: cnt)
buffer.deinitialize(count: cnt)
buffer.deallocate()
}

会申请内存空间,存储每个对象定义copy的返回对象。注意的是如果对象需要实现copy方法。cocoa自带的对象一般都有默认实现。

对于NSArray、NSDictionary应使用copy来保证它们的封装性

如果使用比如strong修饰,当NSMutableArray的实例赋给属性时,属性就变成了NSMutableArray,

由于strong修饰,属性指向了可变数组的内存区域,如果可变数组改变了,属性也会跟随改变反之亦然,

再有,此种情况运行时调用addObject:依然有效,因为isa已经不是NSArray了

block

为什么不能修改截获的自动变量的值

我们知道,block会把截获的自动变量设置成自身的属性

在block内部修改值,相当于设置了自身的属性,但是却无法改变原本的自动变量的值(全局变量,静态变量除外),这样就造成矛盾了。

也就是在oc代码中,明明在block中修改了自动变量的值,结果却没有改变!

所以有了__block修饰符来说明意图

经__block修饰的变量会被编译套壳 __Block_byref

1
2
3
4
5
6
7
8
9
10
11
struct __blockContext_block_impl_0 {
struct __block_impl impl;
struct __blockContext_block_desc_0* Desc;
__Block_byref_alan_0 *alan; // by ref
__blockContext_block_impl_0(void *fp, struct __blockContext_block_desc_0 *desc, __Block_byref_alan_0 *_alan, int flags=0) : alan(_alan->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};

在注释// by ref 可见意图,通过指针引用来间接修改值。

block属性只是自动变量的指针,在block内部通过属性找到自动变量的指针,进而改变值可以改变外部自动变量的值

1
2
3
4
5
6
7
8
9
int alan
// ↓
struct __Block_byref_alan_0 {
void *__isa;
__Block_byref_alan_0 *__forwarding;
int __flags;
int __size;
int alan;
};

关键是__forwarding

1
2
3
4
5
6
// block修改自动变量的部分
static void __blockContext_block_func_0(struct __blockContext_block_impl_0 *__cself) {
__Block_byref_alan_0 *alan = __cself->alan; // bound by ref

(alan->__forwarding->alan) = 2;
}
1
2
// block外部的自动变量的声明
__attribute__((__blocks__(byref))) __Block_byref_alan_0 alan = {(void*)0,(__Block_byref_alan_0 *)&alan, 0, sizeof(__Block_byref_alan_0), 1};
1
2
// 把自动变量赋给block
((void (*)())&__blockContext_block_impl_0((void *)__blockContext_block_func_0, &__blockContext_block_desc_0_DATA, (__Block_byref_alan_0 *)&alan, 570425344));

在block内部想改变外部的自动变量时,获取到的是外部变量壳对象的引用

通过引用找到__forwarding再找到真正的属性变量进行赋值

为什么不直接使用 alan->alan 即通过偏移直接赋值呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
void (*tryBlock)(void) = ((void (*)())&__blockContext_block_impl_0((void *)__blockContext_block_func_0, &__blockContext_block_desc_0_DATA, alan));

struct __blockContext_block_impl_0 {
struct __block_impl impl;
struct __blockContext_block_desc_0* Desc;
int alan;
__blockContext_block_impl_0(void *fp, struct __blockContext_block_desc_0 *desc, int _alan, int flags=0) : alan(_alan) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
//
void (*tryBlock)(void) = ((void (*)())&__blockContext_block_impl_0((void *)__blockContext_block_func_0, &__blockContext_block_desc_0_DATA, (__Block_byref_alan_0 *)&alan, 570425344));

Block 的copy

swift 内存布局

swift如何实现多态

Grand Central Dispatch

Posted on 2020-05-01 | Edited on 2020-05-06

进程

进程:运行中的程序

程序本身是没有生命周期的,只是存储在磁盘中的一些指令或是静态数据,是操作系统将这些字节运行起来,让程序发挥作用。

操作系统提供运行中的程序的抽象,就是所谓的进程。

程序是如何转化为进程的?操作系统是如何启动程序的?

首先操作系统将磁盘中的代码和静态数据加载到内存,加载到进程的地址空间(程序以可执行的格式存储在磁盘中),然后初始化堆栈,当这些准备工作完成后,操作系统找到程序的入口main,将CPU的控制权交给这个创建的进程,而后,程序开始运行了。

An abstract thread quality of service (QOS) classification.

iOS weak

Posted on 2020-04-21 | Edited on 2020-04-22

objc-weak

安全漏洞

Posted on 2020-03-31 | Edited on 2020-08-11

缓冲区溢出错误是造成大多数网络和Internet服务器上安全漏洞的主要原因。

描述一下堆栈原理和缓冲区溢出错误。

如何降低攻击威胁

程序性能

Posted on 2020-03-31

一个switch语句是否总是比一系列的if-else语句高效得多

一个函数调用的开销有多大

while循环比for循环更有效吗

指针引用比数组索引更有效吗

为什么将循环求和的结果放到一个本地变量中,会比将其放到一个通过引用传递过来的参数中,运行起来快很多呢

为什么我们只是简单地重新排列一下算术表达中的括号就能让函数运行得更快

Compilers

Posted on 2020-03-24

参考资料

wikipedia

GCC vs. Clang/LLVM: An In-Depth Comparison of C/C++ Compilers

A Performance-Based Comparison of C/C++ Compilers

12…4

douCodeLife

33 posts
19 tags
© 2021 douCodeLife
Powered by Hexo v3.8.0
|
Theme – NexT.Gemini v7.1.1