iOS基础知识点

2017-06-18  本文已影响12人  随意啊

最近看简书上一些面试题,抽时间整理了一份答案。


1、为什么说Objective-C是动态语言?

  1. 什么是动态语言:</br>       所谓的动态类型语言,意思就是类型的检查是在运行时做的。 </br>      动态语言是在运行时改变其结构:新的函数可以被引进,已有的函数可以被删除或改变,如JavaScript。而C、C++ 等语言则不属于动态语言
  2. 静态类型语言:</br>     静态类型语言的类型判断是在运行前判断(如编译阶段),比如C#、Java就是静态类型语言,静态类型语言为了达到多态会采取一些类型鉴别手段,如继承、接口,而动态类型语言却不需要,所以一般动态语言都会采用dynamic typing,常出现于脚本语言中.需要明确说明一点,那就是,是不是动态类型语言与这门语言是不是类型安全的完全不相干的,不要将它们联系在一起!

优缺点:</br>静态类型语言的主要优点在于其结构非常规范,便于调试,方便类型安全;缺点是为此需要写更多的类型相关代码,导致不便于阅读、不清晰明了。动态类型语言的优点在于方便阅读,不需要写非常多的类型相关的代码;缺点自然就是不方便调试,命名不规范时会造成读不懂,不利于理解等。顺便说一下,现在有这样一种趋势,那就是合并动态类型与静态类型在一种语言中,这样可以在必要的时候取长补短,Boo就是一个很好的试验性例子

  1. Objective-C的动态性:
    </br>      objective-c语言是C语言的一个子类,所以Objective-C是一个静态语言,但是Objective-C的三大特性之一的多态性让其拥有了动态性,oc的动态性让程序可以在运行时判断其该有的行为,而不是像c等静态语言一样在编译构建时就确定下来
typedef struct objc_object {
  Class isa;
} 
/*根类NSObject同样也只有一个Class成员*/
@interface NSObject 

{
  Class isa;
}
// 一个对象的isa指向了这个对象的类Class,而这个对象的类Class的isa指向了metaclass或者class,找到对应的静态方法(+方法)或者实例方法(-方法)。

类的实例对象的isa指向它的类;</br>类的isa指向该类的metaclass;</br>类的super_class指向其父类,</br>如果该类为根类则值为NULL;
metaclass的isa指向根metaclass,如果该metaclass是根metaclass则指向自身;
metaclass 的super_class指向父metaclass如果该metaclass是根metaclass则指向该metaclass对应的类;
</br>Object-C为每个类的定义生成两个objc_class,一个普通的 class,另一个即metaclass。我们可以在运行期创建这两个 objc_class数据结构,然后使用objc_addClass将class注册到运行时系统中,以此实现动态地创建一个新的类

2、MVC/MVP/MVVM

引用文章:杂谈: MVC/MVP/MVVM

1. MVC:</br>概念:

MVC最早存在于桌面程序中的, M是指业务数据, V是指用户界面, C则是控制器. 在具体的业务场景中, C作为M和V之间的连接, 负责获取输入的业务数据, 然后将处理后的数据输出到界面上做相应展示, 另外, 在数据有所更新时, C还需要及时提交相应更新到界面展示. 在上述过程中, 因为M和V之间是完全隔离的, 所以在业务场景切换时, 通常只需要替换相应的C, 复用已有的M和V便可快速搭建新的业务场景. MVC因其复用性, 大大提高了开发效率, 现已被广泛应用在各端开发中.

2.MVP:

MVC的缺点在于并没有区分业务逻辑和业务展示, 这对单元测试很不友好. MVP针对以上缺点做了优化, 它将业务逻辑和业务展示也做了一层隔离, 对应的就变成了MVCP. M和V功能不变, 原来的C现在只负责布局, 而所有的逻辑全都转移到了P层.

mvp的全称为Model-View-Presenter,Model提供数据,View负责显示,Controller/Presenter负责逻辑的处理。MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller。

</br>      相对于MVC, 它其实只做了一件事情, 即分割业务展示和业务逻辑. 展示和逻辑分开后, 只要我们能保证V在收到P的数据更新通知后能正常刷新页面, 那么整个业务就没有问题. 因为V收到的通知其实都是来自于P层的数据获取/更新操作, 所以我们只要保证P层的这些操作都是正常的就可以了. 即我们只用测试P层的逻辑, 不必关心V层的情况.

3.MVVM:

MVVM是Model-View-ViewModel的简写。微软的WPF带来了新的技术体验,如Silverlight、音频、视频、3D、动画……,这导致了软件UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了 诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性糅合进去,以应对客户日益复杂的需求变化。

MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点:

  1. 低耦合。View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
  2. 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
  3. 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,生成xml代码。
  4. 可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

3.为什么代理要用weak?代理的delegate和dataSource有什么区别?block和delegate的区别

1.delegate为什么要用weak:</br>

为了避免循环引用,假如a使用b的代理</br>为什么代理要用weak

@interface Dog : NSObject
 /* weak:指明该对象并不负责保持delegate这个对象,delegate这个对象的销毁由外部控制 */
@property (nonatomic, weak) id<DogDelegate>delegate;
 /* strong:该对象强引用delegate,外界不能销毁delegate对象,会导致循环引用(Retain Cycles) */
@property (nonatomic, strong)id<Dog_strongDelegate>delegate_strong;

2.delegate和dataSource的区别:</br>

dataSource是数据源,是用来连接数据的,delegate是代理函数,用来实现方法的。
dataSource我们需要关心的是我有什么数据,需要传递什么数据或者属性给dataSourse数据源,</br>delegate 我们需要关心的是这个函数我可以用来做什么

3.block和代理的区别</br>

无论是block还是delegate模式本质上都是回调,使用block,其优点是回调的block代码块直接就放在了block赋值的地方,使代码更为紧凑,缺点是block内使用到当前类的实例变量的时候,需要注意循环引用的问题,即需要使用__block(MRC下)或者__weak(ARC下)定义一个弱引用的self出来,block里面使用弱引用的self去操作属性或调用方法。delegate模式不用像block一样做特殊处理,但是如果多个对象设置的代理是同一个对象,就需要在delegate方法中判断当前执行代理的是哪个对象。

4.属性的实质是什么?包括哪几个部分?属性默认的关键字都有哪些?@dynamic关键字和@synthesize关键字是用来做什么的?

--

1.属性的实质是什么:
2.属性默认的关键字
关键字 注释
readwrite 读写属性 默认属性
readonly 只读属性,可以获取不能设置
assign 基本数据类型、直接赋值、不会使引用计数+1
retain 引用计数+1
copy 建立一个索引计数为1的对象,在赋值时使用传入值的一份拷贝
nonatomic 非原子性访问,多线程并发访问会提高性能
atomic 线程安全
strong 强引用 相当于retain
weak 弱引用、当引用计数为0时对应的指针变量变为nil
3.@synthesize和@dynamic
4.属性的默认关键字是什么
5.NSString为什么要用copy关键字,如果用strong会有什么问题?(注意:这里没有说用strong就一定不行。使用copy和strong是看情况而定的)
@property (nonatomic, strong) NSString *strong_String;

@property (nonatomic, copy) NSString *cop_String;

 self.strong_String = @"strong__abcdefg";
    self.cop_String =@"copy__abcdefg";
    NSMutableString *mutableString =[NSMutableString stringWithString:@"123456789"];
    self.strong_String = mutableString;
    self.cop_String = mutableString;
    NSLog(@"mutableString:%@--- strong_String:%@ \n cop_String:%@",mutableString,self.strong_String,self.cop_String);
    [mutableString appendString:@"abcdefg"];
     /* strong_String 的值跟随mutableString发生了改变 cop_String的值没有变*/
     NSLog(@"mutableString:%@--- strong_String:%@ \n cop_String:%@",mutableString,self.strong_String,self.cop_String);
     //mutableString123456789abcdefg--- strong_String123456789abcdefg 
 cop_String123456789

     
6.如何使自己所写的类居右copy功能

若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopyiog 与NSMutableCopying 协议,不过一般没什么必要,实现 NSCopying 协议就够了

// 实现不可变版本拷贝
- (id)copyWithZone:(NSZone *)zone; // 实现可变版本拷贝
- (id)mutableCopyWithZone:(NSZone *)zone;
// 重写带 copy 关键字的 setter
- (void)setName:(NSString *)name {
    _name = [name copy];
}
7.可变集合类 和 不可变集合类的 copy 和 mutablecopy有什么区别?如果是集合是内容复制的话,集合里面的元素也是内容复制么?
 /* 不可变对象 */
    NSString *string =@"abcdefg";
    NSString *copy_string = [string copy]; /* 浅复制 只复制指针 */
    NSMutableString *mutable_copy_string =[string mutableCopy]; /* 深复制 复制内容 即新开辟一块内存地址 */
    /* 打印地址 
     string abcdefg----0x104e7e078
     copy abcdefg----0x104e7e078
     mutableCopy abcdefg----0x60800006a100 */
     
     /* 可变对象 */
    NSMutableString *mutableString =[NSMutableString stringWithString:@"mutable_abcdefg"];
    NSMutableString *copy_mutableString =[mutableString copy];/* 深复制 复制内容 即新开辟一块内存地址 */
    NSMutableString *mutable_copy_mutableString =[mutableString mutableCopy];/* 深复制 复制内容 即新开辟一块内存地址 */
    /* 打印地址
     string mutable_abcdefg----0x60000007e4c0
     copy mutable_abcdefg----0x6000000459d0
     mutableCopy mutable_abcdefg----0x60000007bac0 */
    
     /* 系统的容器类对象:指NSArray,NSDictionary等 */
    NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
    NSArray *copy_array = [array copy]; /* 浅复制 只复制指针 */
    NSMutableArray *mutable_copy_array =[array mutableCopy]; /* 容器本身是深复制 里边的元素是浅复制 */
    [mutable_copy_array addObject:@"de"];
     /* 所有数组的a 都变成了head 说明容器深复制只是复制了本身,里边的元素仍然是复制的指针 */
    NSMutableString *testString =[array objectAtIndex:0];
    [testString appendString:@"head"];
     
8.nonatomic和atomic的区别?atomic是绝对的线程安全么?为什么?如果不是,那应该如何实现?

atomic加锁原理

@property (assign, atomic) int age;

- (void)setAge:(int)age
{ 

    @synchronized(self) { 
       _age = age;
    }
}

5.进程和线程的区别?同步异步的区别?并行和并发的区别?

6.线程间的通信

  • 一个线程传递数据给另一个线程
  • 在一个线程中执行完特定任务后,转到另一个线程继续执行任务
  • NSThread可以先将自己的当前线程对象注册到某个全局的对象中去,这样相互之间就可以获取对方的线程对象,然后就可以使用下面的方法进行线程间的通信了,由于主线程比较特殊,所以框架直接提供了在主线程执行的方法
  • GCD
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

   开启一个全局队列的子线程
   dispatch_async(dispatch_get_global_queue(0, 0), ^{
         
           // 数据请求完毕
           //我们知道UI的更新必须在主线程操作,所以我们要从子线程回调到主线程
       dispatch_async(dispatch_get_main_queue(), ^{

               //我已经回到主线程更新
       });

   });

7.NSCache优于NSDictionary的几点?

NSCache类和NSDictionary很相似,提供key,value的存储,不一样的是NSCache在内存吃紧的时候会做自动释放。
      例如遇到一个问题是,在使用大量图片的app中,需要从存储里面读取数据,每次都从文件系统里面读取文件会造成卡顿现象。
解决办法就是把NSData对象缓存起来,先从NSCache里面读取数据,然后再从文件系统获取数据,提高效率

8.实现description方法能取到什么结果

description方法默认返回对象的描述信息(默认实现是返回类名和对象的内存地址)

9.objc使用什么机制管理对象内存?

ARC和MRC

通过 retainCount 的机制来决定对象是否需要释放。每次 runloop 的时候,都会检查对象的 retainCount,如果retainCount 为 0,说明该对象没有地方需要继续使用了,可以释放掉了。

引用 2017年5月iOS招人心得(附面试题)

上一篇 下一篇

猜你喜欢

热点阅读