iOS

作者: Simple_Code | 来源:发表于2020-08-14 15:04 被阅读0次
1.逆向

1.利用Reveal、LookIn通过图形界面化的形式查看一些竞品或者一些主流APP的UI结构实现。
2.通过CyCript代码形式查看一些APP的UI结构实现、也可暂时性的修改一些UI显示。
3.利用Clutch、Dumpdecrypted、Frida-ios-dump对从AppStore下载的APP进行脱壳,推荐使用Frida-ios-dump、可以脱壳市场上大部分的APP。
4.利用Theos通过Hook修改APP的功能、并打包生产插件,逆向别人的APP。
5.把逆向过的APP进行重签名、可以打包发布到蒲公英等分发平台供用户使用。

2.RunLoop

RunLoop是通过内部维护的事件循序来对事件/消息进行管理的一个对象。
RunLoop有事做的时候做事、没事做的时候休息。
没事做的时候 用户态->内核态
当接收到消息 内核态->用户态

怎样实现一个常驻线程?
1.为当前线程开启一个RunLoop。
2.向该RunLoop种添加一个Port/source等维持RunLoop的事件循环。
3.开启该RunLoop

image.png image.png image.png
3.Runtime

1.是oc比较底层的一门语言。
2.主要体现在消息传递和消息转发。


image.png

消息传递主要是isa指针和SuperClass指针。
isa指针负责水平方向-实例对象->类对象->元类对象查找对象和方法。
superClass负责垂直方向由子类到父类寻找。

消息转发:

4个函数


image.png
image.png
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    // 如果是test方法,打印日志
    if (sel == @selector(testMessage)) {
        NSLog(@"resolveInstanceMethod:");
        return NO;
    } else {
        // 返回父类的默认调用
        [super resolveInstanceMethod:sel];
    }
    return YES;
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"forwardingTargetForSelector:");
    return nil;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(testMessage)) {
        NSLog(@"methodSignatureForSelector:");
        // v 代表返回值void类型的 @i代表第一个参数的类型是id 即self
        // : 代表第二个参数是SEL类型的,即@selector(testMessage)
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    } else {
        return [super methodSignatureForSelector:aSelector];
    }
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"forwardInvocation:");
}

如果经过消息传递和消息转发还没有找到对应的方法就会报常见的unrecoginize message的错误

4.RunLoop UI卡顿

介绍下屏幕成像原理:
水平信号之后在一定频率的时间内同步垂直信号,如果在该频率内未能同步垂直信号、则导致屏幕出现卡顿的现象
CPU:
1.尽量使用轻级的对象 用CALayer代替UIView
2.不要频繁的调用view的相关属性,frame,bounds,transform等、尽量减少不必要的修改
3.Autolayout比frame消耗更过的cpu资源
4.图片的Size尽量和UIImageView的大小保持一致
5.把耗时操作放到子线程
GPU:
1.减少视图的层级和数量
2.减少透明的视图(alpha < 0),不透明的设置为opaque = yes
3.尽量避免出现离屏渲染
4.尽量避免短时间内加载多张图片,尽可能将多张图片合成一张显示
5.GPU不能超过其处理的最大纹理

UITableView 性能优化

1.缓存高度
2.异步绘制
3.按需加载
4.设置view的不透明度为YES.(渲染时系统会进行优化操作)
5.减少Cell上面子控件的数量
6.尽量不要动态的去创建Cell的子控件、通过Hidden隐藏或显示
7.刷新数据时,如果只是刷新某个cell或者section,不需要通过[tableView relodatea]来刷新。
8.Cell上存在图片时,尽量不要加载大的图片。通过后台设置多图的形式避免。
9.将负责耗时的操作放到子线程去执行。
10.复杂的页面尽量避免阴影的操作。
11.懒加载

5.强引用和弱引用

强引用:当前对象被其他对象引用时,会执行retain操作,引用计数器+1。当retainCount=0时,该对象才会被销毁。因为我们要进行对象的内存管理,所以这是默认的引用方式。(默认是强引用)

弱引用:当前对象的生命周期不由其他对象引用限制,它本该什么时候销毁就什么时候被销毁。即使它的引用没断,但是当它的生存周期到了时就会被销毁。

在定义属性时,若声明为retain类型的,则就是强引用;若声明为assign类型的,则就是弱引用。后来内存管理都由ARC来完成后,若是强引用,则就声明为strong;若是弱引用,则就声明为weak。
weak:对象销毁之后会自动置为nil,防止野指针。

weak变量是怎样添加到弱引用表中的?

当使用如下代码

id __weak obj1 = obj;

经过编译之后会变成:

id obj1;
objc_initWeak(&obj1,obj);

一个被声明为__weak的对象指针,经过编译器的编译之后,会调用objc_initWeak()方法,经过一系列的函数调用栈,最终会在weak_register_no_lock()函数中进行弱引用变量的添加,具体添加的位置是通过Hash算法来进行位置查找的,如果查找过程中已经有了当前对象对应的弱引用数组,就把这个新的弱引用变量添加到这个数组中,如果没有的话,就重新创建一个弱引用数组,把这个新的弱引用变量添加到第0个位置,后面的都置为nil。 其中具体的实现过程可以在苹果官网查看相应的源码实现。

清除weak变量,同时设置置为nil

当一个weak 对象被dealloc之后,dealloc内部会去调用弱引用清除的相关函数,然后调用weak_clear_no-lock()函数,根据当前指针查找弱引用表,找到当前对象相对应的弱引用数组,遍历这个数组的所有弱引用指针,分别置为nil.

内存管理:
https://www.jianshu.com/p/f4aabbb72b04

6. Block
1.block有哪几种类型?

__NSGlobalBlock __ ( _NSConcreteGlobalBlock )
__NSStackBlock __ ( _NSConcreteStackBlock )
__NSMallocBlock __ ( _NSConcreteMallocBlock )

代码展示block的三种类型:

int age = 1;
void (^block1)(void) = ^{
    NSLog(@"block1");
};

void (^block2)(void) = ^{
    NSLog(@"block2:%d",age);
};

NSLog(@"%@/%@/%@",[block1 class],[block2 class],[^{
    NSLog(@"block3:%d",age);
} class]);

输出结果:
__NSGlobalBlock __/__NSMallocBlock __/__NSStackBlock __

2.如何判断block是哪种类型?

1.没有访问auto变量的block是__NSGlobalBlock __ ,放在数据段
2.访问了auto变量的block是__NSStackBlock __
3.[__NSStackBlock __ copy]操作就变成了__NSMallocBlock __

3.在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上的几种情况?

1.block作为函数返回值时
2.将block赋值给__strong指针时
3.block作为Cocoa API中方法名含有usingBlock的方法参数时
4.block作为GCD API的方法参数时

内存布局.png

参考地址

7. 内存管理

内存管理的三种方式

TaggedPointer
NONPOINTER_ISA
散列表

SideTable:

spinlock_t 自旋锁
RefcountMap 引用计数表
weak_table_t 弱引用表

引用计数: 谁创建,谁释放。

MRC:手动引用计数管理
ARC:自动引用计数管理

自动释放池:

什么是自动释放池?

autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作。 如果对象的引用计数>1如何处理

简述自动释放池的原理?

autorelease实际上只是把对release的调用延迟了,对于每一个autorelease,系统只是把该 Object放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用release。

自动释放池的优点是什么?

不用再关心对象释放的时间
不用再关心什么时候调用release

基本使用

1)方法一:

NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];
Person *p = [[[Person alloc] init] autorelease];
[autoreleasePool release];

2)方法二:

@autoreleasepool {
    // 创建一个自动释放池
    Person *p = [[[Person alloc]init] autorelease];
} // 销毁自动释放池(会给池子中所有对象发送一条release消息)

可参考内容

8.响应链和事件传递

响应者:

在iOS中,响应者为能响应事件的UIResponder子类对象,如UIButton、UIView等。

响应链:

响应链是由链接在一起的响应者(UIResponse子类)组成的。默认情况下,响应链是由第一响应者,到application对象以及中间所有响应者一起组成的。

事件传递:

获得响应链后,将事件由第一响应者往application传递的过程即为事件传递。

9.子线程的Runloop是默认关闭的
10.深拷贝和浅拷贝

深拷贝:值类型 -拷贝一个新的对象
浅拷贝:引用类型 -拷贝是指针、指向的是同一块内存

strong、copy

1.不可变类型使用strong、如果使用copy的话会发生崩溃。
2.如果引入指向不可变类型的话,使用strong修饰不可变类型是浅拷贝,使用copy修饰不可变类型是深拷贝,一般修饰不可变会选择copy

相关文章

网友评论

      本文标题:iOS

      本文链接:https://www.haomeiwen.com/subject/twgddktx.html