面试遇到的问题整理

作者: marlonxlj | 来源:发表于2017-01-06 17:12 被阅读55次

    面试问题:

    本次时间:2017-1-6

    前言:面试都会遇到各种各样的人和各种各样的问题,以下是总结遇到的问题的。大部分的问题都是可以网上找到答案的。

    有的没有整理完善,等有空了再做更新。
    1.get和post的区别

    Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE

    (1)GET使用URL或Cookie传参。而POST将数据放在BODY中。
    (2)GET的URL会有长度上的限制,则POST的数据则可以非常大。
    (3)POST比GET安全,因为数据在地址栏上不可见。

    具体:

    get请求和post请求都可以用于做获取数据请求

    在请求数据安全方面post请求比get请求安全

    get是以明文的方式向服务器发送请求

    post是包装到请求体body中后,在向服务器发送请求

    get请求的参数全部暴露在接口中,一般叫做明文请求或者傻瓜式请求,post请求的参数一般是以字典的方式进行拼接,相对于get比较安全

    如果从服务器获取数据,或者查询数据,使用get请求;如果上传数据到服务器或者修改服务器上传数据使用post请求

    get请求的URL在使用过程中,会限制长度,因此长度非常长的请求建议用
    post请求

    对文件大小的请求:get不允许向服务器上传文件(图片,pdf,音视频)

    2.runtime机制,具体使用;objc_class的属性有哪些?在接手同事的一个项目时,使用runtime打印出每一个控制器的方法?或者是类别,都知道类别是不能添加属性的,但是想给它添加成员属性,runtime怎么做?

    成员变量操作

    // 1. 获取类中指定名称实例成员变量的信息
    Ivar class_getInstanceVariable ( Class cls, const char *name );
     
    // 2. 获取类成员变量的信息
    Ivar class_getClassVariable ( Class cls, const char *name );
     
    // 3. 添加成员变量
    BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
     
    // 4. 获取整个成员变量列表
    Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
    

    属性操作函数:

    // 获取指定的属性
    objc_property_t class_getProperty ( Class cls, const char *name );
     
    // 获取属性列表
    objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
     
    // 为类添加属性
    BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
     
    // 替换类的属性
    void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
    

    3.SDWebImage的源码?他的原理是怎么样?

    4.在使用AFNetworking请求数据的时候,在一个页面需要同时请求多个接口的数据,需要在所有数据都请求成功后才能刷新tableview应该怎么做?

    5.内存管理的基本机制或原理;原则有哪些?

    原则:

    MRC:
    当使用new、alloc或copy方法创建一个对象时,该对象引用计数器为1。如果不需要使用该对象,可以向其发送release或autorelease消息,在其使用完毕时被销毁。

    ARC:无效

    关键字:

    1. assign: 默认修饰符,表示简单赋值,一般用于(int, char,double,NSInteger等等)类型的基本数据类型.

    2. readonly: 表示"只读",只会生get方法.

    3. readwrite: 表示"读写",会生成set,get方法. 默认修饰符

    4. setter: 指定set方法的新名字(给set方法起一个新的名字)

    5. getter: 指定get方法的新名字(给get方法起一个新的名字)

    6. copy: 所修饰的成员变量,在对成员变量使用set方法设置值时,会将成员变量将要指向的对象重新复制一份,让成员变量指向新复制的对象.

    复制一个新的对象.(浅拷贝):字符串、block变量、使用copy
    mutableCopy:复制的是一个指针地址.(深拷贝)

    1. strong: 在arc中作业对象成员的默认修饰符.strong修饰的指针,指向一个对象,对象的引用计数加1.当不再指向的对象销毁时,指针会发送release消息.

    2. weak:修饰的指针,指向一个对象,不会retain,当指向的对象被销毁时,指针会自动变为nil;weak id<Delegate> delegate block用(copy).

    3. unsafe_unretained,修饰的指针,指向一个对象,不会retain,当指向的对象被销毁时,指针也不会变为nil.

    6.gcd、创建线程
    GCD:是把任务放到队列中执行
    任务:同步、异步;同步是一个一个的执行;异步是可以同时执行多个
    队列:并发、串行;一个一个的执行是并发;可以同时多个执行的是串行

    dispatch_queue_t queue = dispatch_queue_create("test", nil);//创建一个队列
    dispatch_async(queue, ^{//    创建异步线程
        for (int i = 0; i < 100; i++) {
            NSLog(@"多线程6==%d",i);
        }
    NSLog(@"多线程");
    
    //用多线程请求网络数据
    
    dispatch_sync(dispatch_get_main_queue(), ^{// 回到主线程
    // 一般在主线程更新界面
        });
    });
    
    [self mainThread]; //执行主线程
    
    

    7.二维码使用的是第三方还是自己的,如何解决扫描图像不清析的问题?

    • 生成二维码
      • 实例化二维码滤镜
      • 恢复滤镜的默认属性
      • 将字符串转换成NSData
      • 通过KVC设置滤镜inputMessage数据,通过KVC设置滤镜的 inputCorrectionLevel (容错率)
      • 获得滤镜输出的图像
      • 将CIImage转换成UIImage,并放大显示
      • 通过位图创建高清图片
    • 识别二维码

      • 创建一个上下文
      • 创建一个探测器
      • 转换原图片为 CIImage
      • 获取探测器识别的图像特征
      • 遍历图片特征, 获取数据
      • 绘制识别到的二维码边框
      • 传递识别的数据给外界
    • 扫描二维码

      • 实例化拍摄设备

      • 设置输入设备

      • 设置元数据输出处理对象

        • 实例化拍摄元数据输出
        • 设置输出数据代理
      • 添加拍摄会话

      • 启动会话

      • 监听元数据处理后的结果

    8.蓝牙技术的问题?

    9.https请求的问题?

    10.指针问题?

    11.设计模式

    12.页面加载的生命周期

    • init-初始化程序
    • viewDidLoad-加载视图
    • viewWillAppear-UIViewController对象的视图即将加入窗口时调用;
    • viewDidApper-UIViewController对象的视图已经加入到窗口时调用;
    • viewWillDisappear-UIViewController对象的视图即将消失、被覆盖或是隐藏时调用;
    • viewDidDisappear-UIViewController对象的视图已经消失、被覆盖或是隐藏时调用;

    13.程序的生命周期

    • Not running: 未运行,程序未启动
    • Inactive:未激活:程序在前台运行,不过没有接收到事件。在没有事件处理情况下程序
      通常停留在这个状态
    • Active: 激活:程序在前台运行而且接收到了事件。这也是前台的一个正常的模式
    • Backgroud:后台:程序在后台而且能执行代码,大多数程序进入这个状态后会在在这个
      状态上停留一会。时间到之后会进入挂起状态(Suspended)。有的程序经过
      特殊的请求后可以长期处于Backgroud状态
    • Suspended:挂起:程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会
      发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就
      把挂起的程序清除掉,为前台程序提供更多的内存。
    //1. 告诉代理进程启动但还没进入状态保存
    - (BOOL)application:(UIApplication *)application 
    willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    
    //2. 告诉代理启动基本完成程序准备开始运行
    - (BOOL)application:(UIApplication *)application
     didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    
    //3. 当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件,比如来电话了
    - (void)applicationWillResignActive:(UIApplication *)application
    
    //4. 当应用程序入活动状态执行
    - (void)applicationDidBecomeActive:(UIApplication *)application 
    
    //5. 当程序被推送到后台的时候调用。所以要设置后台继续运行,则在这个函数里面设置即可
    - (void)applicationDidEnterBackground:(UIApplication *)application
    
    //6. 当程序从后台将要重新回到前台时候调用
    - (void)applicationWillEnterForeground:(UIApplication *)application
    
    //7. 当程序将要退出是被调用,通常是用来保存数据和一些退出前的清理工作。这个需要设置UIApplicationExitsOnSuspend的键值。 
    - (void)applicationWillTerminate:(UIApplication *)application
    
    //8. 当程序载入后执行
    - (void)applicationDidFinishLaunching:(UIApplication*)application
    
    
    

    14.MVC模式

    MVC图片

    Model

    • 模型对象封装了应用程序的数据,并定义操控和处理该数据的逻辑和运算

    View

    • 视图对象是应用程序中用户可以看见的对象。视图对象知道如何将自己绘制出来,并可能对用户的操作作出响应

    Controller

    • 在应用程序的一个或多个视图对象和一个或多个模型对象之间,控制器对象充当媒介。控制器对象因此是同步管道程序,通过它,视图对象了解模型对象的更改,反之亦然。

    总结:

    • Model和View永远不能相互通信,只能通过Controller传递。
    • Controller可以直接与Model对话(读写调用Model),Model通过Notification和KVO机制与Controller间接通信。
    • Controller可以直接与View对话,通过outlet,直接操作View,outlet直接对应到View中的控件,View通过action向Controller报告事件的发生(如用户Touch我了)。Controller是View的直接数据源(数据很可能是Controller从Model中取得并经过加工了)。Controller是View的代理(delegate),以同步View与Controller。

    15.MVVM模式

    16.为什么block使用copy

    当用__block来修饰变量int aa = 10 的时候,在block内部调用变量aa的时候,使用的是在相同内存空间中修改过的变量aa的值,即变量aa的值从10修改为了100。那么此时打印aa得到的结果就是修改过的值100,且地址还是开始声明aa的时候所开辟的内存空间的地址

    原因是:当变量aa未使用__block修饰的时候,block会将“捕捉”到的变量复制一份,然后对复制品进行操作。也就是说预编译的时候,block已经把变量aa复制了一份出来(可以理解为重新声明了一个同名的变量,此时的两个变量在内存中的地址是不同的),当最后一句代码执行了block调用的时候,block内部使用的是自己复制(本质上是深拷贝)出来的一个变量

    17.关于为什么使用weak而不是用assign来对delegate进行标注?
    delegate一般的类型都是id,即可以指向所有对象的id类型。所以我们既可以使用assign指向他,也可以使用weak指向他。但是因为weak在不被持有的时候会指向nil,所有通过nil的方法在调用函数的时候,都会返回为nil,这样就能够保证了程序的稳定性,就算没有东西返回,他还是能够正常解析(只是解析出来的值为nil)。而如果使用assign的话,如果一不持有他。那么下次再调用它的时候,他将会指向一个不知名的地址,即野指针。这样就会使得整个程序crash。

    18.数据持久化的区别,什么时候使用哪一个效果更好?

    分为四类:
    1. 文件、或是沙盒目录存储:分三个目录
    • DocumentsiTunes同步该应用时会同步此文件夹中的内容,适合存储重要数据.
    NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    
    
    • Library/Caches: iTunes不会同步此文件夹,适合存储体积大,不需要备份的非重要数据.
    NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    
    
    • Library/Preferences: iTunes同步该应用时会同步此文件夹中的内容,通常保存应用的设置信息。
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    
    
    • /tmp: iTunes不会同步此文件夹,系统可能在应用没运行时就删除该目录下的文件,所以此目录适合保存应用中的一些临时文件,用完就删除.
    NSString *path = NSTemporaryDirectory();
    
    
    NSString *filePath = [[self getDocumentPath] stringByAppendingString:@"fileTest.txt"];
    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"3316368400@qq.com", @"email", @"3316368400@qq.com", @"emailDisplay", nil];
    [dictionary writeToFile:filePath atomically:YES];
    
    1. 归档(NSKeyedArchiver)

    归档(又名序列化),把对象转为字节码,以文件的形式存储到磁盘上,程序运行过程中或者再次重新打开程序的时候,可以通过解归档(返序列化)还原这些对象。

    • 归档的对象是Foundation框架中的对象
    • 归档和解归档其中任意对象都需要归档和解归档整个文件
      归档后的文件是加密的,所以归档文件的扩展名可以随意取
    • 在带键的归档中,每个归档都有一个key值,解归档时key值要与归档时key值匹配
    • 如果一个自定义的类A,作为另一个自定义类B的一个属性存在;那么,如果要对B进行归档,那么,B要实现NSCoding协议。并且,A也要实现NSCoding协议.
    [NSKeyedArchiver archiveRootObject:obj toFile:appSettingPath];//会调用对象的encodeWithCoder方法
    
    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        [aCoder encodeObject:_name forKey:kAddressCardName];
        [aCoder encodeObject:_emailObj forKey:kAddressCardEmail];
        [aCoder encodeInteger:_salary forKey:kAddressCardSalary];
    }
    
    [NSKeyedUnarchiver unarchiveObjectWithFile:appSettingPath];//会调用对象的initWithCoder方法
    - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
    {
        _name = [aDecoder decodeObjectForKey:kAddressCardName];
        _emailObj = [aDecoder decodeObjectForKey:kAddressCardEmail];
        _salary = [aDecoder decodeIntegerForKey:kAddressCardSalary];
        return self;
    }
    
    
    3. 属性列表(NSUserDefaults)

    NSUserDefaults支持基本数据类型:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL,NSData.

    • 应用域(application domain)是最重要的域,它存储着你app通过NSUserDefaults set...forKey添加的设置。
    • 注册域(registration domain)仅有较低的优先权,只有在应用域没有找到值时才从注册域去寻找。
    • 全局域(global domain)则存储着系统的设置
    • 语言域(language-specific domains)则包括地区、日期等
    • 参数域(argument domain)有最高优先权
    注意:

    偏好设置是专门用来保存应用程序的配置信息的,一般不要在偏好设置中保存其他数据。

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:@"marlonxlj" forKey:@"userName"];
    [defaults setInteger:28 forKey:@"Age"];
    //同步
    [defaults synchronize];
    
    
    4. 数据库(SQLite、CoreData、第三方类库

    主要存储大文件,数据量大的时候采用.

    coreData:它使开发者可以把数据当做对象来操作,而不必在乎数据在磁盘中的存储方式。

    • 持久化存储协调器NSPersistentStoreCoordinator
    • 托管对象模型NSManagedObjectModel
    • 托管对象上下文NSManagedObjectContext
    
    模型文件操作
    
    1.1 创建模型文件,后缀名为.xcdatamodeld。创建模型文件之后,可以在其内部进行添加实体等操作(用于表示数据库文件的数据结构)
    
    1.2 添加实体(表示数据库文件中的表结构),添加实体后需要通过实体,来创建托管对象类文件。
    
    1.3 添加属性并设置类型,可以在属性的右侧面板中设置默认值等选项。(每种数据类型设置选项是不同的)
    
    1.4 创建获取请求模板、设置配置模板等。
    
    1.5 根据指定实体,创建托管对象类文件(基于NSManagedObject的类文件)
    
    实例化上下文对象
    
    2.1 创建托管对象上下文(NSManagedObjectContext)
    
    2.2 创建托管对象模型(NSManagedObjectModel)
    
    2.3 根据托管对象模型,创建持久化存储协调器(NSPersistentStoreCoordinator)
    
    2.4 关联并创建本地数据库文件,并返回持久化存储对象(NSPersistentStore)
    
    2.5 将持久化存储协调器赋值给托管对象上下文,完成基本创建。
    
    
    // 从应用程序包中加载模型文件
        NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
        // 传入模型对象,初始化持久化存储协调器
        NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
        // 构建SQLite数据库文件的路径
        NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        NSURL *url = [NSURL fileURLWithPath:[docs stringByAppendingString:@"person"]];
        // 添加持久化存储器,用sqlite作为存储库
        NSError *error = nil;
        NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];
        if(store == nil)
        {
            [NSException raise:@"添加数据库失败" format:@"%@", [error localizedDescription]];
        }
        // 创建托管对象上下文
        NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        context.persistentStoreCoordinator = psc;
        
    
    NSManagedObject *card = [NSEntityDescription insertNewObjectForEntityForName:@"Card" inManagedObjectContext:context];
        [card setValue:@"4768558865" forKey:@"no"];
        [person setValue:card forKey:@"card"];
        // 利用上下文对象,将数据同步到持久化存储库
        NSError *errorSave = nil;
        BOOL sucess = [context save:&errorSave];
        
    
    // 从数据库查询数据
        NSFetchRequest *request = [[NSFetchRequest alloc] init];
        request.entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];
        NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
        request.sortDescriptors = [NSArray arrayWithObject:sort];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@", @"MJ55*"];
        request.predicate = predicate;
        // 执行请求
        NSError *errorFetch = nil;
        NSArray *objs = [context executeFetchRequest:request error:&errorFetch];
        if(errorFetch)
        {
            [NSException raise:@"查询错误" format:@"%@", [errorFetch localizedDescription]];
        }
    

    19.copy、mutableCopy区别?

    [对象:copy]
    [对象:mutableCopy]

    对于不可变对象,copy只是拷贝了对象的地址.mutableCopy才是拷贝了一个新的对象.
    对于可变对象,copy,mutableCopy都是拷贝一个新的对象.

    [注]对于自定义类的对象不是随便就可以使用copy,mutableCopy拷贝一个新对象,自定义类必须遵从NSCoping/NSMutableCopy协议.并且实现协议中的copyWithZone:/mutableCopyWithZone:方法.这样才可以实现对自定义对象的拷贝.

    对于不可变对象,copy是浅拷贝,mutableCopy是深拷贝.
    对于可变对象:copy,mutableCopy都是深拷贝.

    20.runloop如何唤醒?比如当程序开始运行的时候去检测一个沙盒目录的文件
    应用场景举例:主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为"Common"属性。DefaultMode 是 App 平时所处的状态,TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态。当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。

    CFRunLoopSourceRef 是事件产生的地方。Source有两个版本:Source0 和 Source1。

    • Source0 只包含了一个回调(函数指针),它并不能主动触发事件。使用时,你需要先调用 CFRunLoopSourceSignal(source),将这个 Source 标记为待处理,然后手动调用 CFRunLoopWakeUp(runloop) 来唤醒 RunLoop,让其处理这个事件。
    • Source1 包含了一个 mach_port 和一个回调(函数指针),被用于通过内核和其他线程相互发送消息。这种 Source 能主动唤醒 RunLoop 的线程

    CFRunLoopTimerRef 是基于时间的触发器,它和 NSTimer 是toll-free bridged 的,可以混用。其包含一个时间长度和一个回调(函数指针)。当其加入到 RunLoop 时,RunLoop会注册对应的时间点,当时间点到时,RunLoop会被唤醒以执行那个回调。

    CFRunLoopObserverRef 是观察者,每个 Observer 都包含了一个回调(函数指针),当 RunLoop 的状态发生变化时,观察者就能通过回调接受到这个变化。

    系统默认注册了5个Mode:

    1. kCFRunLoopDefaultMode: App的默认 Mode,通常主线程是在这个 Mode 下运行的。
    2. UITrackingRunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。
    3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用。
    4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到。
    5. kCFRunLoopCommonModes: 这是一个占位的 Mode,没有实际作用。

    20.Category中添加属性和成员变量的区别?

    objc_getAssociatedObject / objc_setAssociatedObject来访问和生成关联对象

    
    #import <UIKit/UIKit.h>
    
    @interface UIImage (XLJName)
    
    @property (nonatomic, copy) NSString *XLJ_imageName;
    
    @end
    
    
    
    #import "UIImage+XLJName.h"
    #import <objc/runtime.h>
    
    static const void *XLJ_imageNameKey = &XLJ_imageNameKey;
    
    @implementation UIImage (XLJName)
    
    - (NSString *)XLJ_imageName
    {
        return objc_getAssociatedObject(self, XLJ_imageNameKey);
    }
    
    - (void)setXLJ_imageName:(NSString *)XLJ_imageName
    {
        objc_setAssociatedObject(self, XLJ_imageNameKey, XLJ_imageName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    

    21.iOS 中调用 self.name= 与 _name="" 的区别?

    self.name =”object”:会调用对象的setName()方法;
    name = “object”:会直接把object赋值给当前对象的name属性。

    22.obj-c有私有方法吗?私有变量吗?

    由于Objective-C的动态消息传递机制,OC中不存在真正意义上的私有方法。
    但是如果你不在.h文件中声明,只在.m文件中实现,或在.m文件的Class Extension里声明,那么基本上和私有方法差不多。

    23.MVC是什么设计模式,你还熟悉什么设计模式?

    MVC是一种复合模式

    (1)模型:模型持有所有的数据、状态和程序逻辑。模型独立于视图和控制器。

    (2)视图:用来呈现模型。视图通常直接从模型中取得它需要显示的状态与数据。对于相同的信息可以有多个不同的显示形式或视图。

    (3)控制器:位于视图和模型中间,负责接受用户的输入,将输入进行解析并反馈给模型,通常一个视图具有一个控制器。

    设计模式分为三大类:

    1.创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

    2.结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

    3.行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

    4.并发型模式

    5.线程池模式。

    设计模式的六大原则:

    总原则-开闭原则
    对扩展开放,对修改封闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。
    想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。

    1、单一职责原则
    不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,否则就应该把类拆分。

    2、里氏替换原则(Liskov Substitution Principle)
    任何基类可以出现的地方,子类一定可以出现。里氏替换原则是继承复用的基石,只有当衍生类可以替换基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
    里氏代换原则是对“开-闭”原则的补充。实现“开闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。

    3、依赖倒转原则(Dependence Inversion Principle)
    面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。

    4、接口隔离原则(Interface Segregation Principle)
    每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。

    5、迪米特法则(最少知道原则)(Demeter Principle)
    一个类对自己依赖的类知道的越少越好。无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。
    最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。

    6、合成复用原则(Composite Reuse Principle)
    尽量首先使用合成/聚合的方式,而不是使用继承。

    24.系统自带的线程池(NSOpertionQueue)的作用?

    凡是需要启动多个线程的地方都可以使用NSOpertionQueue,加入到NSOpertionQueue中的对象都需要继承NSOpertion。 NSOpertionQueue会在系统内部启动一个独立线程去执行这个被加入对象的main方法。

    常用的地方是用nsoprationqueue 下载图片,文件。如果是自己创建一个线程池,无非就是启动多个线程的时候,

    把这些线程对象放到一个大数组中,如果需要启动线程的时候,先从数组中找空闲线程来使用。

    自己管理线程池最大的难题是不好处理当启动多个线程后,用户在多个界面的跳转的时候,对线程方法的回调管理。

    而NSOpertionQueue可以很好的处理他。

    25.类别有什么作用?继承和类别在实现中有何区别?

    category 可以在不获悉,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改。
    category:类、种类
    并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级.

    类别跟类的优先级

    类别主要有3个作用:

    (1)将类的实现分散到多个不同文件或多个不同框架中。

    (2)创建对私有方法的前向引用。

    (3)向对象添加非正式协议。

    继承可以增加,修改或者删除方法,并且可以增加属性。

    非正式协议:是使用类别category来实现,非正式协议是NSObject的一个类别,这样任何类的对象都可以作为委托对象来使用,它可以列出对象能够执行的所有方法,这样用来实现委托, 我们可以使用选择器来判断该非正式协议中是否有这个方法。

    正式协议:是一个命名的方法列表,与非正式协议相比不同的是,它要求显示的采用协议,采用协议的方法是在类的@interface声明中列出协议的名称,此时,实现协议的类应该遵守协议,承诺实现协议中的所有方法。

    26.ios平台怎么做数据的持久化?Coredata和sqlite有无必然联系?coredata是一个关系型数据库吗?

    比如写入沙盒(其实是一个本应用程序才可以访问的路径),因为sqlite是c语言的api。 你的问题问的是数据库相关,比如存到网络上,还提供了一些管理的功能,比如写入数据库,然而有人也需要obj-c 的api,core data不仅仅是把c的api翻译成oc 的api,但从逻辑上又分成很多种, Core data与sqlite还是有联系的,core data 是对sqlite的封装,所以有了 core data 另外,使用更加方便数据的持久化本质上都是就是写文件,那么针对它讨论

    27.让一个物体从界面的一个点到另一个点,有哪些方法?

    28.以下每行代码执行后,persion对象的retaion count是多少?

            Persion *persion = [[Persion alloc] init];
            NSLog(@"1---%lu--= 1", (unsigned long)persion.retainCount);
            [persion retain];
            
            NSLog(@"2---%lu -- = 2", (unsigned long)persion.retainCount);
            
            [persion release];
            NSLog(@"3---%lu --= 1", (unsigned long)persion.retainCount);
            
            [persion release];
            NSLog(@"4---%lu --= 1", (unsigned long)persion.retainCount);
    
    

    29.你在开发项目中时,用到了哪些数据存储方式,iphone中常见的方式有哪些,各有什么区别?

    数据存储五种形式的应用范围和性能区别

    (core data, sqllite,对象序列化,文件直接读写,NSUserDefault(保存数据到temp文件夹中)) 文件直接读写 >core data> 对象序列化> sqllite>NSUserDefault.

    代码规范

    • 命名规范
      • 1). 常量的命名
      • 2). 枚举的命名
      • 3). 变量和对象的命名
    • 编码规范:三个原则:可复用, 易维护, 可扩展
      • 1). 判断nil或者YES/NO
      • 2). 条件赋值
      • 3). 初始化方法
      • 4). 定义属性
      • 5). BOOL赋值
        1. 拒绝死值
      • 7). 复杂的条件判断
      • 8). 嵌套判断
      • 9). 参数过多
      • 10). 回调方法
    • Block的循环引用问题
      • __wealk

    ####🐼🐶🐶如果对你有帮助,或觉得可以。请右上角star一下,这是对我一种鼓励,让我知道我写的东西有人认可,我才会后续不断的进行完善。


    ###有任何问题或建议请及时issues me,以便我能更快的进行更新修复。


    ####Email: marlonxlj@163.com

    相关文章

      网友评论

        本文标题:面试遇到的问题整理

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