iOS 笔试面试题

1、为什么说OC是一门动态语言?

主要体现以下三个方面: 动态类型、动态绑定

 (1) 动态类型 : 即运行时再决定对象的类型。简单说就是id类型,任何对象都可以被id指针所指,只有在运行时才能决定是什么类型。
 例如 : `NSString *string = [[NSData alloc]init];`
 编译时 是  NSString 类型,运行时 却是  NSData 类型 

 (2) 动态绑定 :基于动态类型,在某个实例对象被确定后,其类型便被确定了。该对象对应的属性和响应的消息也被完全确定,这就是动态绑定。

 例如 :我们一般向一个NSObject对象发送-respondsToSelector:或者 -instancesRespondToSelector:等来确定对象是否可以对某个SEL做出响应,而在OC消息转发机制被触发之前,对应的类 的+resolveClassMethod:和+resolveInstanceMethod:将会被调用,在此时有机会动态地向类或者实例添加新的方 法,也即类的实现是可以动态绑定的。

2、frame和bouns的区别

  frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)
  bounds指的是:该view在本身坐标系统中 的位置和大小。(参照点是本身坐标系统)
  例如:view的frame是{10,10,50,50},bounds就是{0,0,50,50}; 
  bounds可理解成边界

3、UIView和CALayer的区别和联系

(1) UIView主要用来响应事件,CALayer不可以
    原因:UIView继承UIResponder(在UIResponder中定义了处理各种事件和事件传递的接口),CALayer继承NSObject 
(2) UIView是CALayer的代理对象,实现其代理方法drawRect,从而绘制出了 UIView 的内容,CALayer比UIView多了个AnchorPoin(锚点)
(3) 两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews

4、+ (void)load+(void)initialize 的区别

(1) 二者都是定义在NSObject中的静态方法
(2) 在不考虑主动调用的情况下,二者默认都只会被调用一次。
   load 方法会在加载类的时候就被调用(在main方法前),initialize在类的方法第一次被调时执行(main方法后)
(3)load方法是在程序启动之前就调用,父类先于子类执行,类先于分类执行
(4)load经常被用来做交换IMP操作,initialize用于初始化静态变量

5、import、include、@class区别。import"" 和import<>的区别

  (1)  #import和#include都能完整地包含某个文件的内容,#import能防止同一个文件被包含多次
  (2) @class仅仅是声明一个类名,并不会包含类的完整声明;@class还能解决循环包含的问题
  (3)#import <> 用来包含系统自带的文件,#import “”用来包含自定义的文件

备注: @class 只是声明,例如,我用block回调一类型变量出来,我可能会调用变量的某个方法。例如,简单的removeSuperView,这时候 Receiver type ‘’ for instance message is a forward报错。就知道应该要import。

6、OC中的数字对象都有哪些,与基本数据类型的区别是什么

 oc中用NSNumber类来包装基本数据类型,基本类型只是一个值,没有任何行为。

**7、weak 和 assign 的区别 **

    (1) weak 和 assign 都是弱引用声明类型
    (2) weak只能在ARC下使用,只能修饰对象
    (3) ARC下,指针变量一定要用weak修饰,
               只有基本数据类型和结构体需要用assgin
    (3) ARC下,如果用weak声明的变量在栈中就会自动清空,赋值为nil。
              如果用assign声明的变量在栈中可能不会自动赋值为nil,
              就会造成野指针错误!
    (4)weak使用规则:只要还有一个变量指向对象,对象就会保持在内存中

8、Category 和 Extension 的区别

  Category的作用 :
           
     (1)category的主要作用是为已经存在的类添加方法,不能扩充成员变量,
     如果要空充变量,可以使用runtime动态添加
     objc_setAssociatedObject 和 objc_getAssociatedObject 完成
     (2) 如果category中的方法和类中原有方法同名,运行时会优先调用category中的方法。
     这也就是我们平常所说的category的方法会“覆盖”
     掉原来类的同名方法,这是因为运行时在查找方法的时候是
     顺着方法列表的顺序查找的,它只要一找到对应名字的方法,
     就会罢休,殊不知后面可能还有一样名字的方法。
     
     Extenison的作用 :
     
     (1)能为某个类添加成员变量,属性,方法;
     (2)一般的类扩展写到.m文件中;
     (3)一般的私有属性写到类扩展中
     
     区别 :
     (1) category 是在编译阶段被添加到类中,而Extenison是在运行时添加到类中
     (2) 类扩展不能像类别那样拥有独立的实现部分
        即 类扩展所声明的方法必须依托对应类的实现部分来实现。
     (3) 类扩展不仅可以增加方法,还可以增加实例变量(或者属性),只是该实例变量默认是@private类型的
     (4)定义在 .m 文件中的类扩展方法为私有的,定义在 .h 文件(头文件)中的类扩展方法为公有的。类扩展是在 .m 文件中声明私有方法的非常好的方式。

      注意 : 我自己的理解,extension直接理解成放在实现文件的.h文件。

9、关于 深拷贝 和 浅拷贝

  浅拷贝:指针拷贝,不产生新的对象,源对象的引用计数器+1;(人和影子,互相影响)

  深拷贝:对象拷贝,会产生新的对象,源对象的引用计数器不变;(克隆人,互不影响)

  常见的笔试题目:
  @property (nonatomic, copy) NSMutableArray *mutableArray;
  NSMutableArray *array = [NSMutableArray arrayWithObjects:@1,@2,nil];
  self.mutableArray = array;
  [self.mutableArray removeObjectAtIndex:0];

  细节 : 对可变对象进行copy得到不可变对象,例如,可变数组放对象,
  copy得到一个不可变数组。当对数组里对象进行修改,可变和不可变数组的对象皆修改。
  也就是说,数组中的对象并没有实现真正的拷贝,始终是引用拷贝。Mutablecopy只不过新开辟内存空间而已,对象里面的数据依然是指针复制的。
// copy 性质的setter内部实现
-(void)setmutableArray:(NSMutableArray *)mutableArray
{
    if (_mutableArray != mutableArray) 
    {
        [_mutableArray release];
        _mutableArray = [mutableArray copy];
    }
}

10、如何写一个完整的单例

static ShareInstance *instance =  nil;
+ (id)ShareInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        instance = [[self alloc]init];
        
    });
    
    return instance;    
}//静态方法

+ (instancetype)allocWithZone:(NSZone *)zone
{
    return [self ShareInstance];
}

+ (id)copyWithZone:(struct _NSZone *)zone
{
    return [self ShareInstance];
}
+ (id)mutableCopyWithZone:(struct _NSZone *)zone
{
   
    return [self ShareInstance];    
}

//MRC 增加如下方法
-(oneway void)release
{
    
}
-(instancetype)retain
{
    return instance;
}
-(NSUInteger)retainCount
{
    return MAXFLOAT;
}

11、简述内存管理,autorelease的作用,及autoreleasepool的对象什么时候释放。

  内存管理黄金法则 : 谁创建,谁释放。谁引用,谁管理。
  OC是通过引用计数管理对象的声明周期,当对象通过 new、alloc、retain、拷贝 持有对象的时候,对应对应引用计数+1.那么就有义务对当对象不被使用的情况下release操作,使其引用计数-1。当对应引用计数为0的时候,对象生命周期结束。
  autorelease的作用是声明将对象放入自动释放池。
  当程序处于休眠状态的时候,autoreleasepool会向池中的对象分别发送release消息,对象引用计数-1。当对象的引用计数为0的时候,对象销毁。

12、SDWebImage 如何识别文件格式。

+ (NSString *)sd_contentTypeForImageData:(NSData *)data {
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
            return @"image/jpeg";
        case 0x89:
            return @"image/png";
        case 0x47:
            return @"image/gif";
        case 0x49:
        case 0x4D:
            return @"image/tiff";
        case 0x52:
            // R as RIFF for WEBP
            if ([data length] < 12) {
                return nil;
            }

            NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
            if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
                return @"image/webp";
            }

            return nil;
    }
    return nil;
}

这个文件是NSData的分类,只有一个方法,传入图片数据,根据图片的头标识来确定图片的类型。头标识都不一样,只需获取文件头字节,对比十六进制信息,判断即可。图片的格式存在 图片文件的前8个字节中. 第一个字节 0xFF 则图片为 JPEG , 为 0x89 则为 PNG。

13、IBOutlet 和 IBAction

IB的全称是 Interface Builder 界面构造器

IBOutlet 的属性是 weak :因为当我们将控件拖到Storyboard上,相当于新创建了一个对象,而这个对象是加到视图控制器的view上,view有一个subViews属性,这个属性是一个数组,里面是这个view的所有子view,而我们加的控件就位于这个数组中,那么说明,实际上我们的控件对象是属于view的,也就是说view对加到它上面的控件是强引用。当我们使用Outlet属性的时候,我们是在viewController里面使用,而这个Outlet属性是有view来进行强引用的,我们在viewController里面仅仅是对其使用,并没有必要拥有它,所以是weak的。**如果将weak改为strong,也是没有问题的,并不会造成强引用循环。**当viewController的指针指向其他对象或者为nil,这个viewController销毁,那么对控件就少了一个强引用指针。然后它的view也随之销毁,那么subViews也不存在了,那么控件就又少了一个强引用指针,如果没有其他强引用,那么这个控件也会随之销毁。

IBAction : 方法不能使用 return value。 相当于 void 。

14、UIView中的几个方法:setNeedsLayout、layoutIfNeeded、setNeedsDisplay、setNeedsDisplayInRect:

setNeedsLayout :Invalidates the layer’s layout and marks it as needing an update.作用在于标记需要更新布局,但是不会立即更新

layoutIfNeeded:Recalculate the receiver’s layout, if required. 如果,有需要刷新的标记,立即调用layoutSubviews进行布局

备注: setNeedsLayout 和 layoutIfNeeded 经常配合使用,调用layoutSubViews,即刻更新布局。

setNeedsDisplay 和 setNeedsDisplayInRect: You can use this method or the setNeedsDisplayInRect: to notify the system that your view’s contents need to be redrawn. This method makes a note of the request and returns immediately. The view is not actually redrawn until the next drawing cycle, at which point all invalidated views are updated. 即刻调用 drawRect: 渲染视图

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值