iOS面试资料

2022-02-09  本文已影响0人  JamieChen

iOS面试题

[toc]

一、设计基本原则

简述六大设计基本原则(也称 SOLID 五大原则)

单一职责原则 (SRP, Single Responsibility Principle)

开闭原则(OCP, Open-Close Principle)

里氏替换原则 (LSP,Liskov Substitution Principle)

接口隔离原则(ISP, Interface Segregation Principle)

依赖倒置原则(DIP, Dependence Inversion Principle)

迪米特法则(LOD, Law Of Demeter) / 最小知道原则 (LKP,Least Knowledge Principle)

设计基本原则特点总结

面向对象的三大特征

什么是 MVC 设计模式?

什么是 MVVM?主要目的是什么?有哪些优点?

二、内存管理

引用计数怎么存储?

struct SideTable {
    spinlock_t stock;
    RefcountMap refcnts; // 存放着对象引用计数的散列表
    weak_table_t weak_table;
}

ARC具体为引用计数做了哪些工作?

深拷贝与浅拷贝

对象的拷贝

- (id)copyWithZone:(NSZone *)zone {
    Person *person = [Person allocWithZone:zone];
    person.name = self.name;
    return person;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
    Person *person = [Person allocWithZone:zone];
    person.name = self.name;
    return person;
}

集合对象的拷贝

#import <Foundation/Foundation.h>

@interface Person : NSObject <NSCoding>

@property (nonatomic, copy) NSString *name;

@end


#import "Person.h"

@implementation Person

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self.name = [aDecoder decodeObjectForKey:@"name"];
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.name forKey:@"name"];
}

@end

自动释放池

属性修饰词:Copy、Strong、Weak、Assign

block属性为什么需要用copy来修饰?

代理为什么使用weak修饰?

为什么NSMutableArray一般不用copy修饰?

- (void)setData:(NSMutableArray *)data {
    if (_data != data) {
        [_data release];
        _data = [data copy];
    }
}

拷贝完成后:可变数组->不可变数组,在外操作时(添加、删除等)会存在问题

什么是“僵尸对象”?

有哪些情况会出现内存泄漏

- (void)dealloc底层执行了什么?

- (void)dealloc {
    _objc_rootDealloc(self);
}


void _objc_rootDealloc(id obj) {
    ASSERT(obj);
    obj->rootDealloc();
}


inline void objc_object::rootDealloc() {
    if (isTaggedPointer()) return;  // fixme necessary?

    if (fastpath(isa.nonpointer  &&          // 无优化过isa指针
                 !isa.weakly_referenced  &&  // 无弱引用
                 !isa.has_assoc  &&          // 无关联对象
                 !isa.has_cxx_dtor  &&       // 无cxx析构函数
                 !isa.has_sidetable_rc)) {   // 不存在引用计数器是否过大无法存储在isa中(使用 sidetable 来存储引用计数)
        // 直接释放
        assert(!sidetable_present());
        free(this);
    } else {
        // 下一步
        object_dispose((id)this);
    }
}


// 如果不能快速释放,则调用 object_dispose()方法,做下一步的处理
static id _object_dispose(id anObject) {
    if (anObject==nil) return nil;

    objc_destructInstance(anObject);
    
    anObject->initIsa(_objc_getFreedObjectClass ());

    free(anObject);
    return nil;
}


void *objc_destructInstance(id obj) {
    if (obj) {
        // Read all of the flags at once for performance.
        bool cxx = obj->hasCxxDtor();               // 是否存在析构函数
        bool assoc = obj->hasAssociatedObjects();   // 是否有关联对象

        // This order is important.
        if (cxx) object_cxxDestruct(obj);           // 销毁成员变量
        if (assoc) _object_remove_assocations(obj); // 释放动态绑定的对象
        obj->clearDeallocating();
    }
    return obj;
}


/*
 * clearDeallocating一共做了两件事
 *
 * 将对象弱引用表清空,即将弱引用该对象的指针置为nil
 * 2、清空引用计数表
 * - 当一个对象的引用计数值过大(超过255)时,引用计数会存储在一个叫 SideTable 的属性中
 * - 此时isa的 has_sidetable_rc 值为1,这就是为什么弱引用不会导致循环引用的原因
 */
inline void  objc_object::clearDeallocating() {
    if (slowpath(!isa.nonpointer)) {
        // Slow path for raw pointer isa.
        sidetable_clearDeallocating();
    }
    else if (slowpath(isa.weakly_referenced  ||  isa.has_sidetable_rc)) {
        // Slow path for non-pointer isa with weak refs and/or side table data.
        clearDeallocating_slow();
    }
    assert(!sidetable_present());
}

三、多线程

GCD

GCD核心概念:「任务」、「队列」

如何打造线程安全的NSMutableArray?

如何异步下载多张小图最后合成一张大图?

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /*加载图片1 */ });
dispatch_group_async(group, queue, ^{ /*加载图片2 */ });
dispatch_group_async(group, queue, ^{ /*加载图片3 */ }); 
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 合并图片
});

什么是线程安全?

如何设置常驻线程?🌟🌟

在异步线程发送通知,在主线程接收通知。会不会有什么问题?

GCD线程是如何调度的

如何实现多个任务执行完后,再统一处理?

线程和线程之间如何通信?

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;

示例:

- (void)viewDidLoad {
    [super viewDidLoad];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // 在子线程中调用download方法下载图片
    [self performSelectorInBackground:@selector(download) withObject:nil];
}

- (void)download {
    // 1.根据URL网络中下载图片
    NSURL *urlstr=[NSURL URLWithString:@"fdsf"];

    // 2、把图片转换为二进制的数据, 这一行操作会比较耗时
    NSData *data=[NSData dataWithContentsOfURL:urlstr];

    // 3、把数据转换成图片
    UIImage *image=[UIImage imageWithData:data];

    // 4、回到主线程中设置图片
    [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
}

//设置显示图片
- (void)settingImage:(UIImage *)image {
    self.iconView.image=image;
}

谈谈atomic的实现机制,为什么不能保证绝对线程安全?

  - (void)setCurrentImage:(UIImage *)currentImage {
    if (_currentImage != currentImage) {
        [_currentImage release];
        _currentImage = [currentImage retain];
    }
}

- (UIImage *)currentImage {
    return _currentImage;
}

- (void)setCurrentImage:(UIImage *)currentImage {
    @synchronized(self) {
        if (_currentImage != currentImage) {
            [_currentImage release];
            _currentImage = [currentImage retain];
        }
    }
}

- (UIImage *)currentImage {
    @synchronized(self) {
        return _currentImage;
    }
}

进程和线程的区别

Notification与线程相关

如何实现在不同线程中post和转发一个Notification?

重定向的实现思路:

  1. 自定义一个通知队列(用数组类型),让它去维护那些我们需要重定向的Notification
  2. 我们仍然是像平常一样去注册一个通知的观察者,当Notification来了时,先看看post这个Notification的线程是不是我们所期望的线程
  3. 如果不是,则将这个Notification存储到我们的队列中,并发送一个信号(signal)到期望的线程中,来告诉这个线程需要处理一个Notification
  4. 指定的线程在收到信号后,将Notification从队列中移除,并进行处理

dispatch_once底层实现

线程锁

互斥锁

自旋锁

信号量(Semaphore - dispatch_semaphore_t)

递归锁(NSRecursiveLock)

atomic

线程不安全

四、Block相关

Block

关于block的截获特性,你是否有了解?block的截获变量特性是怎样的?

对栈上的block进行copy之后,假如在mrc环境下,内存是否回泄漏?

为什么block会产生循环引用?

Block不允许修改外部变量的值原因

如何实现对外部变量的捕获?

__block

__block int var = 10;
void(^blk)(void) = ^{
    var = 20;
};
blk();

转换后的代码:

struct __Block_byref_var_0 {
    void *__isa;
    __Block_byref_var_0 *__forwarding;
    int __flags;
    int __size;
    int var; // 10 => 20 该结构体持有相当于原来自动变量的成员变量
};

struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    __Block_byref_var_0 *var; // by ref
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_var_0 *_var, int flags=0) : var(_var->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
};

block在修改NSMutableArray需不需要添加__block

block是如何捕获局部变量的?

UIView动画中block回调里self要不要弱引用?

block里面会不会存在self为空的情况(weak strong的原理)?

__weak typeof(self) weakself = self;
[self wj_refresh_addRefreshHeader:^{
    __strong typeof(weakself) strongself = weakself;
    [strongself.dataSource reloadDataWithCompletion:nil];
}];

__block与__weak的区别

多层block嵌套如何使用weakSelf?

__weak typeof(self) weakself = self;
[self wj_refresh_addRefreshHeader:^{
    __strong typeof(weakself) strongself = weakself;
    __weak typeof(self) weakSelf2 = strongself;
    [strongself.dataSource reloadDataWithCompletion:^(BOOL result) {
        __strong typeof(self) strongSelf2 = weakSelf2;
    }];
}];

Masonry对于block内部引用self会不会造成循环引用?

- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    block(constraintMaker);
    return [constraintMaker install];
}

__weak来解决block中的循环引用,还有别的方法吗

代理、Block利弊

五、Runtime

Runtime的相关术语

SEL、id、Class、Method、IMP、Cache、Property

介绍下runtime的内存模型(isa、对象、类、metaclass、结构体的存储信息等)

为什么要设计metaclass

class_copyIvarList & class_copyPropertyList区别

class_rw_t 和 class_ro_t 的区别

交互两个方法的现实有什么风险?

六、Runloop

/*
 * 从字典中获取,如果没有则直接创建
 */
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
__CFSpinUnlock(&loopsLock);
if (!loop) {
    CFRunLoopRef newLoop = __CFRunLoopCreate(t);
    __CFSpinLock(&loopsLock);
    loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    
    if (!loop) {
        CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
        loop = newLoop;
    }
    
    // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
    __CFSpinUnlock(&loopsLock);
    CFRelease(newLoop);
}

NSTimer相关

NSTimer准吗?如果不准的话原因是什么?如何解决?

使用NSTimer是如何处理循环引用的?

使用类方法
TODO(待填充);

谈谈常用的三种定时器优缺点(NSTimer、CADisplayLink、GCD定时器)✨✨✨✨✨

在viewWillDisappear或者viewDidDisappear方法中将 timer = nil,是否还会造成循环引用?

如何利用runloop监控卡顿✨✨✨

七、KVO

KVO基础

KVO 的 全称Key-Value Observing,俗称“键值监听”,可以用于某个对象属性值的改变

iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么)

如何手动触发KVO?

直接修改成员变量会触发KVO么?

八、KVC

KVC基础

KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性

通过KVC修改属性会出发KVO么?

KVC的赋值和取值过程是怎样的?

使用场景

[self.model setValuesForKeysWithDictionary:dict];
UILabel *placeholderLabel=[self.userTextField valueForKeyPath:@"placeholderLabel"];
placeholderLabel.textColor = [UIColor redColor];
CGFloat sum = [[array valueForKeyPath:@"@sum.floatValue"] floatValue];
CGFloat avg = [[array valueForKeyPath:@"@avg.floatValue"] floatValue];
CGFloat max =[[array valueForKeyPath:@"@max.floatValue"] floatValue];
CGFloat min =[[array valueForKeyPath:@"@min.floatValue"] floatValue];
[dataArray valueForKeyPath:@"@distinctUnionOfObjects.self"]
NSArray *temp1 = @[@3, @2, @2, @1];
NSArray *temp2 = @[@3, @4, @5];
NSLog(@"\n%@",[@[temp1, temp2] valueForKeyPath:@"@distinctUnionOfArrays.self"]);
NSLog(@"\n%@",[@[temp1, temp2] valueForKeyPath:@"@unionOfArrays.self"]);

输出两个数组:( 5, 1, 2, 3, 4 ), ( 3, 2, 2, 1, 3, 4, 5 )。

NSArray *array = @[@"name", @"w", @"aa", @"jimsa"];
NSLog(@"%@", [array valueForKeyPath:@"uppercaseString"]);
打印:
(NAME,W,AA,JIMSA)

九、Category

Category相关

Category的使用场合

Category的实现原理

category和extension区别

分类的局限性

为什么category不能添加属性?使用Runtime就可以了?

Category中有load方法么?load方法什么时候调用的?load方法能继承么?

test方法和load方法的本质区别?(+load方法为什么不会被覆盖)

load调用顺序

不同Category中存在同一个方法,会执行哪个方法?如果是两个都执行,执行顺序是什么样的?

load、initialize方法的区别是什么?它们在category中的调用顺序?以及出现继承时他们之间的调用过程?🌟🌟🌟🌟🌟

区别:

分类中方法替换

为什么不能动态添加成员变量?

十、网络

TCP、UDP

TCP、UDP优点及缺点

TCP、UDP的区别

Scoket连接和HTTP连接的区别

HTTP协议的特点,关于HTTP请求GET和POST的区别

断点续传怎么实现的?

TCP建立和断开连接过程

a、 三次握手
b、 三次握手为什么是三次握手
c、 四次挥手
d、挥手为什么需要四次?
e、为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
f、SYN的初始值(ISN initialization sequence number)是一个随机值

TCP建立连接的三次握手中,第二次握手发送的包会包含的标记,最正确的描述是?

网络层相关

网络七层协议

Charles原理

HTTPS的连接建立流程

TCP分片 和 IP分片

Cookie和Session

DNS是什么?DNS解析过程

HTTP和HTTPS的区别?Https为什么更加安全?

ipv6

十一、UI

Storyboard/Xib和纯代码UI相比,有哪些优缺点?

Auto Layout

Auto Layout基本原理

控制器

描述一下 UIViewController 的生命周期

如果页面 A 跳转到 页面 B,A 的 viewDidDisappear 方法和 B 的 viewDidAppear 方法哪个先调用?

离屏渲染,隐式动画和显式动画相关

离屏渲染触发条件

事件响应过程(响应链)

事件的传递 (寻找最合适的view的过程)

事件的响应

事件顺序

事件穿透

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint yellowPoint = [self convertPoint:point toView:_yellowView];
    if ([_yellowView pointInside:yellowPoint withEvent:event]) {
        return _yellowView;
    }
    return [super hitTest:point withEvent:event];
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint yellowPoint =[_yellowView convertPoint:point fromView:self];
    if ([_yellowView pointInside:yellowPoint withEvent:event]){
        return NO;
    } else {
        return [super pointInside:point withEvent:event];
    }
}

手势识别

手势识别的过程

这里主要说的是关于runloop的概念点

十二、其他

数组和链表

数组和链表的区别

数组和链表的优缺点

静态库、动态库

什么是库?

静态库和动态库的区别

为什么framework既是静态又是动态?

.a 和 .framework 的区别是什么?

NSDictionary

NSDictionary底层实现原理

十三、Objective-C 类和对象相关

语言基础

Objective-C 与 C、C++ 之间的联系和区别是什么?

如何理解 Objective-C 为动态运行时语言?

Objective-C 中是否支持垃圾回收机制?

Objective-C 是支持垃圾回收机制的,但是在 iOS 中不可用,iOS 开发只支持手动内存管理和 ARC(Automatic Reference Counting)。

Objective-C 中堆和栈的区别是什么?

堆空间的内存是动态分配的,一般用于存放 Objective-C 对象,并且需要手动释放内存,不及时回收容易产生内存泄露,ARC 环境下 Objective-C 对象由编译器管理,不需要手动释放;栈空间的内存由系统自动分配,一般存放非 Objective-C 对象的基本数据类型,例如 int、float 等,由系统编译器管理,不需要手动管理内存。

类、对象

OC的类信息存放在哪里?

类与结构体的区别

class、meta-class的结构

struct objc_class : objc_object {
    Class ISA;
    Class superclass;
    cache_t cache;             // 方法缓存
    class_data_bits_t bits;    // 用于获取具体的类信息
}

& FAST_DATA_MASK

struct class_rw_t {
    uint32_t flags;
    uint32_t version;
    const class_ro_t *ro;        // 
    method_array_t methods;      // 方法列表
    property_array_t properties; // 属性列表
    protocol_array_t protocols;  // 协议列表
    Class firstSubclass;
    Class nextSiblingClass;
    char *demangledName;
}

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name; // 类名
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars; // 成员变量列表

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
}

对象的isa指针指向哪里?superclass指针呢?

方法调用查找

class对象的superclass指针

meta-class对象的superclass指针

对象相关

属性可以与set方法和get方法 三者同时存在吗,如果不行,请说明原因?

换句话说就是:iOS中同时重写属性的set与get方法时,为什么访问不了下划线属性?

iOS如何实现多继承,代码书写一下

#import <Foundation/Foundation.h>

@protocol YFPerson <NSObject>
@required
@property (nonatomic,copy,readonly)NSString *name;
- (NSInteger) age;
- (void)eat;
- (void)sleep;
@optional
- (void)play;
- (void)setName:(NSString *)newName;
@end
#import <Foundation/Foundation.h>

@protocol YFChild <NSObject>
@required
- (NSString *)nickname;
- (void)introduceMyselfWithName:(NSString *)name nickname:(NSString *)nickname age:(NSInteger)age;
@optional
- (void)study;
@end
- (NSString *)nickname
{
    return @"龙儿";
}

- (NSInteger)age
{
    return 19;
}

- (void)sleep{
    NSLog(@"sleep");
}

- (void)eat{
    NSLog(@"eat");
}

- (void)introduceMyselfWithName:(NSString *)name nickname:(NSString *)nickname age:(NSInteger)age
{
    NSLog(@"我叫%@,小名%@,今天%@岁了", name,nickname,@(age));
}
- (void)viewDidLoad {
    [super viewDidLoad];
    
    YFStudent *student = [[YFStudent alloc]init];
    student.name = @"小龙女";
    [student eat];
    [student sleep];
    [student introduceMyselfWithName:student.name nickname:student.nickname age:student.age];
}

关键字和系统提供的类

简述__kindof关键字

@property (nonatomic, strong) NSMutableArray<UIView *> *viewList;
👇
@property (nonatomic, strong) NSMutableArray <__kindof UIView *> * viewList;

新版Xcode这个问题已经优化,例子属于老实例,理解这个意思就行了

关于NSProxy


@interface LYBird ()
@property (nonatomic, copy) NSString *bridName;
@end

@implementation LYBird
- (void)onFly {
    NSLog(@"%@正在飞翔", self.bridName);
}
@end



@interface LYFish ()
@property (nonatomic, copy) NSString *fishName;
@end

@implementation LYFish
- (void)onSwimming {
    NSLog(@"%@正在游泳", self.fishName);
}
@end



- (void)viewDidLoad {
    [super viewDidLoad];
    
    LYBird *bird = [[LYBird alloc] init];
    LYFish *fish = [[LYFish alloc] init];
    
    LYProxy *proxy = [LYProxy alloc];
    
    [proxy transformToObject:bird];
    [proxy performSelector:@selector(setBridName:) withObject:@"鹰隼"];
    [proxy performSelector:@selector(onFly)];
    
    [proxy transformToObject:fish];
    [proxy performSelector:@selector(setFishName:) withObject:@"🦈"];
    [proxy performSelector:@selector(onSwimming)];
}

id和NSObject ,instancetype的区别?

nil、Nil、NULL、NSNull的区别?

NSNull在Objective-C中是一个类 .NSNull有 + (NSNull *)null; 单例方法.多用于集合(NSArray,NSDictionary)中值为空的对象.

NSArray *array = [NSArray arrayWithObjects: [[NSObject alloc] init], [NSNull null], @"aaa", nil, [[NSObject alloc] init], [[NSObject alloc] init], nil];
NSLog(@"%ld", array.count);// 输出 3,NSArray以nil结尾

十四、Swift

语言基础

对比 Objective-C,Swift 有什么优势?

在 Swift 中,为什么 map 函数必不可少?该在什么情况下使用它?

在 Swift 中使用扩展可以完成什么任务?

在 Swift 中,什么时候用结构体,什么时候用类?

十五、App优化等

系统架构

iOS 系统可分为四级结构,由上至下分别为可触摸层(Cocoa Touch Layer)、媒体层(Media Layer)、核心服务层(Core Services Layer)、核心操作系统层(Core OS Layer),每个层级提供不同的服务。

低层级结构提供基础服务如文件系统、内存管理、I/O 操作等,高层级结构建立在低层级结构之上提供具体服务如 UI 控件、文件访问等。

可触摸层主要提供用户交互相关的服务如界面控件、事件管理、通知中心、地图,包含的框架主要有 UIKit Framework、Event Kit UI Framework、Notification Center Framework、Map Kit Framework等。

媒体层主要提供图像引擎、音频引擎、视频引擎框架。

核心服务层为程序提供基础的系统服务例如网络访问、浏览器引擎、定位、文件访问、数据库访问等,主要包含框架有 CFNetwork Framework、Core Data Framework、Core Location Framework 和 Web Kit Framework 等。

核心系统层为上层结构提供最基础的服务如操作系统内核服务、本地认证、安全、加速等,主要包含框架有 Accelerate Framework、External Accessory Framework 和 Security Framework 等。

简述一下 iOS 的系统架构

iOS 系统可分为四级结构,由上至下分别为 可触摸层(Cocoa Touch Layer)、媒体层(Media Layer)、核心服务层(Core Services Layer)、核心操作系统层(Core OS Layer),每个层级提供不同的服务。可触摸层主要提供用户交互相关的服务如界面控件、事件管理、通知中心、地图;媒体层主要提供图像引擎、音频引擎、视频引擎框架;核心服务层为程序提供基础的系统服务例如网络访问、浏览器引擎、定位、文件访问、数据库访问等;核心系统层为上层结构提供最基础的服务如操作系统内核服务、本地认证、安全、加速等。

Crash

Crash监控

App启动

打印结果:
Total pre-main time: 238.05 milliseconds (100.0%)              // main函数调用之前(pre-main)总耗时
         dylib loading time: 249.65 milliseconds (104.8%)      // 动态库耗时 
        rebase/binding time: 126687488.8 seconds (18128259.6%) 
            ObjC setup time:  10.67 milliseconds (4.4%)        // OC结构体准备耗时 
           initializer time:  52.83 milliseconds (22.1%)       // 初始化耗时 
           slowest intializers :                               // 比较慢的加载 
             libSystem.B.dylib :   6.63 milliseconds (2.7%)
   libBacktraceRecording.dylib :   6.61 milliseconds (2.7%)
    libMainThreadChecker.dylib :  31.82 milliseconds (13.3%)

项目的优化、性能优化

App启动优化

App 包体积优化

页面浏览速度优化

操作流畅度优化

数据持久化

SQLite

SQLite 数据库的特点有哪些?

请简述几种 SQLite 命令

Core Data

Core Data 是什么?

Core Data 是一个关系型数据库吗?

Core Data 与 SQLite 有无必然联系?

Core Data 与 SQLite 是有联系的,Core Data 是基于 SQLite 数据库的一个封装,底层仍然是使用 SQLite 进行存储数据的。

对比分析 Core Data 和 SQLite 的优缺点

测试

单元测试

什么是单元测试?

单元测试是针对程序的最小单元进行正确性检验的测试工作。

本文参考文章及部分内容来源

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/ios-interview/r1rxtj/

作者:强子ly
链接:https://www.jianshu.com/p/24a9447d70f8

百度百科
https://baike.baidu.com/item/IPv6/172297?fr=aladdin

上一篇 下一篇

猜你喜欢

热点阅读