2019年年初iOS招人心得笔记 答案 (二)

11、Objective-C与C、C++之间的联系和区别?

OC

  1. OC是C的超集,扩展了C语言使它具备面向对象设计的能力。例如类、消息、继承;同时在OC的代码中可以有C和C++语句,它可以调用C的函数,也可以通过C++对象访问方法;
  2. OC不同于C++,尽管都有面向对象的能力,但他们分属不同的学派,OC属于SmallTalk学派,C++属于Simula 67学派(一种早期的面向对象语言)。
  3. OC可以底层系统编程,另一方面可以支持利用动态架构进行开发。

OC于C++的比较

两者都是面向对象设计语言,有很多相似之处,但属于不同的学派,也有不同之处:

  1. 继承:OC不支持多继承,C++支持多继承
  2. 函数调用:OC通过传递消息实现函数调用,而C++直接进行函数调用
  3. 定型:OC是动态类型,所以它的类库比C++容易操作。OC在运行时可以允许根据字符串名字访问方法和类,还可以动态链接和添加库。而C++,对象的静态类型决定你是否可以发消息给它。
  4. 接口:OC采用协议(正式和非正式)的形式定义接口,而C++采用虚函数的形式定义接口
  5. 方法重载:OC不支持方法重载,C++支持方法重载。方法重载就是方法名相同,参数个数相同,但是参数类型不同或者返回值不同。

两者的主要差别是因为OC即支持动态类型也支持静态类型。对于id类型的变量,变量只是一个容器,本身是没有类型的,或者只是属于最基本的类型,所以也不需要强制类型转换。因为编译器不会检查变量类型是否正确,只是运行时如果类型不正确才会产生异常。

而C++是静态语言,编译时会检查类型,所以必须要加上强制类型转换,否则编译器就会报错。

12、UICollectionView自定义layout如何实现?

  1. 创建UICollectionViewLayout子类
  2. 创建UICollectionViewLayoutAttributes子类,用于描述每个cell的size,frame,transform属性。
  3. 重写prepare方法,并在方法内部实现各个cell的size、center等的计算。
  4. 重写layoutAttributesForElements和layoutAttributesForItem方法,方法内部返回UICollectionViewLayoutAttributes实例用于对cell进行布局。
  5. 如果有自定义attribute属性,可以放在UICollectionViewLayoutAttributes类中,并在cell实现类的applyLayoutAttributes方法中为每个cell进行属性赋值。

13、进程和线程的区别?同步异步的区别?并行和并发的区别?

  • 进程和线程
    进程:一个正在运行的程序可以看做一个进程。(例如:正在运行的QQ就是一个进程),进程拥有独立运行所需的全部资源。
    线程:程序中独立运行的代码段。(例如:接收QQ消息的代码)
    一个进程是由一或多个线程组成。进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。

  • 同步和异步
    同步是指:当程序1调用程序2时,程序1停下不动,直到程序2完成回到程序1,程序1才继续执行下去。
    异步是指:当程序1调用程序2时,程序1径直继续自己的下一个动作,不受程序2的影响。
    或者
    同步是指:发送方发出数据后,等接受方发挥响应以后才发下一个数据包的通信方式
    异步是指:发送方发出数据后,不等接收方发回响应,接着发送下一个数据包的通讯方式。

  • 并行和并发
    并行(parallel):同一时刻可以互不干扰的同时做几件事


    并行.png

并发(concurrency):统一时间段做几件事


并发.png

并发的解决方案:

  1. 队列和缓冲区
  2. 争抢锁资源
  3. 预处理
  4. 并行
  5. 提速
  6. 消息中间件(RabbitMQ)

参考链接
https://www.jianshu.com/p/c334f8198f9b

14、线程间通信?

线程间通信的体现:
一个线程传递数据给另一个线程
在一个线程中执行玩特定任务后,转到另一个线程继续执行任务

常用的线程间通信的方法

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

15、GCD的一些常用的函数?(group,barrier,信号量,线程同步)

GCD的使用很简单:

  1. 创建一个队列(串行队列和并行队列)
  2. 将任务追加到等待队列中,然后系统就会根据任务的类型执行(同步执行和异步执行)

dispatch_queue_create
dispatch_barrier_async
dispatch_after
dispatch_once
dispatch_apply

dispatch_group
dispatch_group_notify
dispatch_group_wait
dispatch_group_enter
dispatch_group_leave

信号量的作用在于处理多线程任务访问资源限制的问题,有时候也用于上锁和解锁的问题。
dispatch_semaphore_create
dispatch_semaphore_signal 增加信号量
dispatch_semaphore_wait 减少信号量

/**
 * 线程安全:使用 semaphore 加锁
 * 初始化火车票数量、卖票窗口(线程安全)、并开始卖票
 */
- (void)initTicketStatusSave {
    NSLog(@"currentThread---%@", [NSThread currentThread]);
    NSLog(@"semaphore---begin");
    
    self.semaphoreLock = dispatch_semaphore_create(1);
    
    self.ticketSurplusCount = 50;
    
    dispatch_queue_t queue1 = dispatch_queue_create("net.bujige.testqueue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("net.bujige.testqueue2", DISPATCH_QUEUE_SERIAL);
    
    __weak typeof(self) weakSelf = self;
    
    dispatch_async(queue1, ^{
        [weakSelf saleTicketSafe];
    });
    
    dispatch_async(queue2, ^{
        [weakSelf saleTicketSafe];
    });
}
/**
 * 售卖火车票(线程安全)
 */
- (void)saleTicketSafe {
    while (1) {
        //相当于加锁
        dispatch_semaphore_wait(self.semaphoreLock, DISPATCH_TIME_FOREVER);
        
        if (self.ticketSurplusCount > 0) {
            self.ticketSurplusCount--;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%zd 窗口: %@", self.ticketSurplusCount, [NSThread currentThread]]);
            [NSThread sleepForTimeInterval:0.2];
        } else {
            NSLog(@"所有火车票已售完");
            dispatch_semaphore_signal(self.semaphoreLock);
            break;
        }
        //相当于解锁
        dispatch_semaphore_signal(self.semaphoreLock);
        
    }
}

参考链接:
https://www.jianshu.com/p/2d57c72016c6
https://www.jianshu.com/p/189a09d669de

16、如何访问并修改一个类的私有属性?

访问以及修改私有属性的两种方式:
KVC
runtime
objc_msgSend() 通过私有属性的setter和getter方法实现

KVC

setValue:forKey:
valueForKey:

-(void)way1{
    PrivateVariablesClass *classA = [[PrivateVariablesClass alloc] init];
    [classA setValue:@(4) forKey:@"_priviteNum"];
    [classA setValue:self.view forKey:@"_priviteView"];
    [classA showPropertyPrivateVariablesClass];
}

runtime

-(void)way2{
    PrivateVariablesClass *classA = [[PrivateVariablesClass alloc] init];
    
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList([PrivateVariablesClass class], &outCount);
    
    for (int i = 0; i < outCount; i ++) {
        Ivar ivar = ivars[i];
        
        const char *ivarName = ivar_getName(ivar);
        
        //这里要注意ARC下, 这个会报错
        /**
         在修改NSInteger型变量的时候,ARC下,编译器不允许你将NSInteger类型的值赋值给id,在buildsetting中将Objective-C Automatic Reference Counting修改为No即可。但是这样工程就会变成MRC,所以,如果是非对象类型就不建议用object_setIvar这样的方法去修改了。
         */
 
        int a = strcmp(ivarName, "_priviteNum");
        if (strcmp(ivarName, "_priviteNum") == 0) {
            //这种方式传值int类型会报错,不能传入
            object_setIvar(classA, ivar, 22);
        }
        
        if (strcmp(ivarName, "_priviteView") == 0) {
            object_setIvar(classA, ivar, self.view);
        }
    }
    
    [classA showPropertyPrivateVariablesClass];
}

使用ivar_getName()获取属性名并使用object_setIvar()修改属性值,使用获取的属性名通过valueForKey:修改属性值

objc_msgSend()

-(void)way3{
    PrivateVariablesClass *classA = [[PrivateVariablesClass alloc] init];
    ((void (*)(id, SEL, int))(void *) objc_msgSend)((id)classA, @selector(setPriviteNum:) , 33);
    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)classA, @selector(setPriviteView:) , self.view);
    [classA showPropertyPrivateVariablesClass];
}

17、数据持久化的几个方案(fmdb用没用过)

  • plist文件(属性列表)
  • preference(偏好设置)
  • NSKeyedArchiver(归档)
  • SQLite 3
  • CoreData

FMDB的三个主要的类:

  • FMDatabase
    一个FMDatabase对象就代表一个单独的SQLite数据库,用来执行SQL语句
  • FMResultSet
    使用FMResultSet执行查询后的结果集
  • FMDatabaseQueue
    用于在多线程中执行多个查询和更新,它是线程安全的

CoreData

iOS10以后使用NSPersistentContainer来管理数据库对象。NSPersistentContainer中包括NSManagedObjectContext、NSManagedObjectModel、NSPersistentStoreCoordinator。

不是太复杂的模型修改,CoreData都可以自动迁移数据,我们只需要重新生成table映射的model文件即可。

数据库文件默认存放在Library/Application Support文件夹中

参考链接
https://www.jianshu.com/p/7616cbd72845
https://www.jianshu.com/p/6e048f7c5812

18、说一下AppDelegate的几个方法?从后台到前台调用了哪些方法?第一次启动调用了哪些方法?从前台到后台调用了哪些方法?

  1. 应用启动,并进行初始化时调用:aaplication:didFimnishLanuchingWithOptions:
  2. 应用进入前台并处于活动状态时候调用:applicationDidBecomeActive:
  3. 应用从活动状态进入到非活动状态:applicationWillResignActive:
  4. 应用进入到后台时候调用的方法:applicationDidEnterBackground:
  5. 应用进入到前台时候调用的方法:appplicationWillEnterForeground:
  6. 应用被终止的状态:applicationWillTeminate:

从后台到前台调用了哪些方法?
appplicationWillEnterForeground:
applicationDidBecomeActive:

第一次启动调用了哪些方法?
aaplication:didFimnishLanuchingWithOptions:
applicationDidBecomeActive:

从前台到后台调用了哪些方法?
applicationWillResignActive:
applicationDidEnterBackground:

19、NSCache优于NSDictionary的几点?

  1. NSCache具有自动删除的功能,以减少系统占用的内存
  2. NSCache是线程安全的,不需要加线程锁;
  3. 键对象不会像NSMutableDictionary中那样被复制。(NSCache的key只是对对象的strong引用,对象不需要实现NSCopying协议,NSCache也不会像NSDictionary一样复制对象)。

20、知不知道Designated Initializer?使用它的时候有什么需要注意的问题?

指定初始化函数 vs 便利初始化函数

  1. 子类如果有指定初始化函数,那么指定初始化函数实现时必须调用它的直接父类的指定初始化函数。


    image.png
  2. 子类如果有指定初始化函数,那么便利初始化函数必须调用自己的其他初始化函数(包括指定初始化函数以及其他的便利初始化函数),不能调用super的初始化函数。


    image.png
  3. 如果子类提供了指定初始化函数,那么一定要实现所有父类的指定初始化函数。


    image.png
image.png

当 initWithCoder: 遇到 NS_DESIGNATED_INITIALIZER

  • 如果父类没有实现NSCoding协议,那么应该调用父类的指定初始化函数
  • 如果父类实现了NSCoding协议,那么子类的initWithCoder:的实现中需要调用父类的initWithCoder:方法

实现NSCoding协议的时候,我们可以显示的声明 initWithCoder: 为指定初始化函数(一个类可以有多个指定初始化函数,比如UIViewController)即可完美解决问题,既满足了指定初始化函数的三个规则,又满足了NSCoding协议的三条原则。

总计归纳

  • 便利初始化函数只能调用自己类中的其他初始化方法
  • 指定初始化函数才有资格调用父类的指定初始化函数
image.png

参考文章
https://www.cnblogs.com/smileEvday/p/designated_initializer.html

21、实现description方法能取到什么效果?

NSLog(@"%@",object);
调试的时候方便打印对自己有用的信息

22、objc使用什么机制管理对象内存?

ARC自动引用计数

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,067评论 1 32
  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述?设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型...
    龍飝阅读 2,113评论 0 12
  • 中国向来就是礼尚往来的国家。礼数也一直是我们从小到大学习的规矩。 比如,朋友结婚,邀请你吃饭,你会带红包参加婚礼,...
    阿_方阅读 259评论 0 0
  • 文 集:1年100万字作 者:爬格子的兔子 关注战隼、大锤、李笑来、彭小六等人或听过樊登读书会的朋友,对元认知这个...
    王大大来了吖阅读 607评论 2 7
  • 场景1:上班很累,还要做家务,做饭。 我的回答:老公,今天上班从早上8点到下午3点,给我忙的一口水都没喝,现在下了...
    周程程爱说大实话阅读 123评论 0 0