iOS开发交流平台iOS开发iOS学习

面试遇到的问题整理

2017-01-06  本文已影响55人  marlonxlj

面试问题:

本次时间: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.二维码使用的是第三方还是自己的,如何解决扫描图像不清析的问题?

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. 文件、或是沙盒目录存储:分三个目录
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;

NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

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:它使开发者可以把数据当做对象来操作,而不必在乎数据在磁盘中的存储方式。


模型文件操作

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.

代码规范

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


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


####Email: marlonxlj@163.com

上一篇下一篇

猜你喜欢

热点阅读