IOS面试

作者: Hither | 来源:发表于2016-02-01 11:50 被阅读4029次

    (一)
    1.简述你对协议的理解:

    a想做一件事却因为一些原因不能做,于是让b遵循a的一些约定,这样b就可以帮助a做事了。协议中包括了遵循方b需要实现的一些方法,以及b能够做的事情。

    2.如何理解ARC自动引用计数机制:

    ARC--自动引用计数 可以用来管理对象的使用以及了解对象的使用情况,当对象引用计数不为0时,对象不会被释放,当对象引用计数为0时 dealloc函数被调用 对象将会被释放。

    3.如何理解retain/copy/assign/release/autorelease/dealloc关键字:

    retain让对象引用计数加1,release让对象引用计数减1,当对象引用计数为0时会调用dealloc 将对象进行释放。copy是你不想让a和b共享一块内存时候,让a和b有各自的内存。在使用基本数据类型的时候需要使用assgin,assgin是直接赋值,会引起对象引用计数加1.

    (1)assign:普通赋值,一般用于基本数据类型,防止循环引用。
    (2)retain:保留计数,获得用户的所有权。
    (3)copy:用来赋值对象,一般字符串使用copy,Foundation中的不可变对象使用copy效果相当于retain,只是引用计数+1.
    (4)nonatomic:非原子性访问,不加同步,多线程并发访问会提高性能。
    

    4.请简述类别和继承有什么联系和区别 以及weak和assgin的区别:

    类别和继承 都会使用父类的中原有的方法和属性,类别是对父类进行扩展,继承是将父类中的属性、方法等保留下来,根据自己的实际情况进行实现。 weak用于各种UI控件和代理,assgin用于基本数据类型。

    继承可以增加,修改,删除方法,还可以增加属性;

    category只能添加属性;

    strong:
    @property (nonatomic, strong) NSString *string1;   
    @property (nonatomic, strong) NSString *string2;
    self.string1 = @"String 1";   
    self.string2 = self.string1;   
    self.string1 = nil;  
    NSLog(@"String 2 = %@", self.string2);  
     结果是:String 2 = String 1由于string2是strong定义的属性,所以引用计数+1,使得它们所指向的值都是@"String 1"
    weak:
    @property (nonatomic, strong) NSString *string1;   
    @property (nonatomic, weak) NSString *string2; 
     self.string1 = @"String 1";   
    self.string2 = self.string1;   
    self.string1 = nil;  
    NSLog(@"String 2 = %@", self.string2);  
    结果是:String 2 = null
     分析一下,由于self.string1与self.string2指向同一地址,且string2没有retain内存地址,而self.string1=nil释放了内存,所以string1为nil。声明为weak的指针,指针指向的地址一旦被释放,这些指针都将被赋值为nil。这样的好处能有效的防止野指针。
    

    5.请简述你对strong和weak关键字的理解 以及_unsafe_unretained与weak的区别:

    strong相当于retain 让对象引用计数加1,防止对象在异常情况下被提前释放,导致crash。weak 弱引用防止产生循环应用无法释放对象和产生野指针。

    strong叫做强引用,在ARC中使用strong告诉编译器帮组我们自动插入retain,weak是普通赋值相当于手动管理内存的assign。
    _unsafe_unretained与weak功能一致,区别在于当指向的对象销毁后,weak会将变量重置为nil,防止调用野指针,产生EXC_BAD_ACCESS这类的错误。

    6.如何实现ARC和MRC的混合编程:

    在targets的build phases选项下Compile Sources下选择要使用arc编译的文件:  在targets的build phases选项下Compile Sources下选择要不使用arc编译的文件, 就会出报错。方法如下,双击它 输入 -fno-objc-arc 即可。
    如果在ARC 工程中 加MRC 加 -fno-objc-arc 如果在MRC 工程中 加 ARC 加 -fobjc-arc

    7.Objective-C是否支持多继承:

    不支持多继承 因为消息机制名字查找发生在运行时而非编译时,很难解决多个基类可能导致的二义性问题 。可以通过消息转发 协议 类别实现与多继承相似的功能。

    8.Objective-C中变量默认是私有的么?方法默认是私有的么?

    变量默认是private,方法默认是public。

    9.#import"".h 和@class+类名的区别:

    import"".h为导入头文件,@class+类名 为前向引用申明。

    1.import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。
    2.在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
    3.在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。
    4.如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。
    所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来.

    10.请简述页面传值都有哪些实现方法:

    Block、 委托协议、 通知、 单例、NSUserDefaults

    11.请简述深拷贝和浅拷贝的区别:

    深拷贝会重新在堆上开辟一块内存空间 是一个全新的对象 指针地址和原来不一样 浅拷贝不会重新开辟一块内存空间 指针和原来是一样的。
    深拷贝和浅拷贝的本质是地址相同,就是浅拷贝,地址不同就是深拷贝。
    浅拷贝是拷贝操作后,并没有进行真正的复制,而是另一个指针也指向了同一个地址。深拷贝操作后,是真正的复制了一份,另一个指针指向了拷贝后的地址。

    浅拷贝:在复制操作时,对于被复制的对象的每一层复制都是指针复制。
    深拷贝:在复制操作时,对于被复制的对象至少有一层复制是对象复制。 完全复制:在复制操作时,对于被复制的对象的每一层复制都是对象复制。

    浅拷贝好比你的影子,你没了,你的影子也没有了;

    深拷贝好比你的克隆人,你没了,你的克隆人还在 ;

    备注:
    retain:始终是浅复制。引用计数每次加一。返回对象是否可变与被复制的对象保持一致。
    copy:对于可变对象为深复制,引用计数不改变;对于不可变对象是浅复制,引用计数每次加一。始终返回一个不可变对象。
    mutableCopy:始终是深复制,引用计数不改变。始终返回一个可变对象。
    不可变对象:值发生改变,其内存首地址随之改变。
    可变对象:无论值是否改变,其内存首地址都不随之改变。
    引用计数:为了让使用者清楚的知道,该对象有多少个拥有者(即有多少个指针指向同一内存地址)。

    12.系统中有哪些对象是单例:

    NSTimer、NSNotification、UIWindow、UIApplication
    自己写单例需要注意:
    不使用GCD:

     // 单例模式实现要点:
    // 1. 废掉构造方法(调用的时候抛出异常)
    // 2. 提供一个类方法向外界返回该类的唯一实例
    - (instancetype)init {
        @throw [NSException exceptionWithName:@"CDSingleton" reason:@"不允许调用构造方法" userInfo:nil];
        // return nil;
    }
    // 此方法由于没有在.h文件中暴露接口相当于是私有方法
    - (instancetype) initPrivate {
        if(self = [super init]) {
            _value = arc4random();
        }
        return self;
    }
    + (instancetype) sharedInstance {
        // static类型的变量拥有全局的生命周期
        static CDSingleton *instance = nil;
        // 使用同步块保证在多线程环境下仍然是单例
        //同步加锁,在多线程中使用,可以使线程安全
        @synchronized(self) {
            if(!instance) {
                instance = [[self alloc] initPrivate];
            }
        }
        return instance;
    }
    

    使用GCD:

    +(instancetype)sharedInstance{
        static HCDSingleton *singleton = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            singleton = [[HCDSingleton alloc]init];
        });
        return singleton;
    }
    

    13.简述你对MVC设计模式的理解:

    MVC : Model - View - Controller 模型负责数据任务 试图负责呈现 以及和用于进行交互 控制器用来控制试图

    model 模型:主要负责存储和操作数据
    view 视图:主要负责展⽰示数据和⽤用户交互
    controller 主要负责将model和view联系起来:
    从网络获取数据->赋值给数据模型->将model的数据传递给view展⽰示(响应view的delegate和datasource⽅方法)->刷新view
    

    14.IOS中那些技术符合观察者模式:

    Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。每次指定的被观察的对象的属性被修改后,KVO自动通知相应的观察者。

    model中定义:
    @interface StockData : NSObject { NSString * stockName; float price;}
    @end
    @implementation StockData
    @end
    
    controller中使用,这里相当于跟模型说,我要收听你的更新广播
    - (void)viewDidLoad{
     [super viewDidLoad]; 
    stockForKVO = [[StockData alloc] init];
     [stockForKVO setValue:@"searph" forKey:@"stockName"]; 
    [stockForKVO setValue:@"10.0" forKey:@"price"]; 
    [stockForKVO addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
     myLabel = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 100, 30 )];
     myLabel.textColor = [UIColor redColor];
     myLabel.text = [stockForKVO valueForKey:@"price"]; 
    [self.view addSubview:myLabel]; 
    UIButton * b = [UIButton buttonWithType:UIButtonTypeRoundedRect];
     b.frame = CGRectMake(0, 0, 100, 30); 
    [b addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
     [self.view addSubview:b];
    }
    
    用户单击View中的button调用控制器中的action去更改模型中的数据
    -(void) buttonAction{
     [stockForKVO setValue:@"20.0" forKey:@"price"];
    }
    
    控制器需要实现的回调,相当于收到广播后我应该做啥事
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    { 
        if([keyPath isEqualToString:@"price"])
         {
           myLabel.text = [stockForKVO valueForKey:@"price"];
         }
    }
    
    注意使用通知和KVO一定要记着移除,否则会导致crash
    视图dealloc需要取消观察
    - (void)dealloc{
     [super dealloc];
     [stockForKVO removeObserver:self forKeyPath:@"price"]; [stockForKVO release];
    }
    

    15.简述你对工厂方法的理解:

    创建对象的时候,我们一般是alloc一个对象,如果需要创建100个这样的对象,如果是在一个for循环中还好说,直接一句alloc就行了,但是事实并不那么如意,我们可能会在不同的地方去创建这个对象,那么我们可能需要写100句alloc 了,但是如果我们在创建对象的时候,需要在这些对象创建完之后,为它的一个属性添加一个固定的值,比方说都是某某学校的学生,那么可能有需要多些100行重复的代码了,那么,如果写一个-(void)createObj方法,把创建对象和学校属性写在这个方法里边,那么就是会省事很多,也就是说我们可以alloc 创建对象封装到一个方法里边,直接调用这个方法就可以了,这就是简单工厂方法。

    16.什么是代理模式,实现代理需要注意什么:

    代理模式:帮助别人完成别人委托你完成的事情。你需要注意遵守别人给你定的约定,和你是否拥有完成这件事的能力。

    17.简述StoryBoard和Xib的联系和区别:

    StoryBoard可以在上面实现整个项目界面的搭建,可以清楚得看到各个试图控制器之间的关系,XIB实现自定义要素和良好部件重用性复杂的UI。

    18.请简述UITableView对CELL的重用机制:

    比如一个屏幕可以放下5个UITableViewCell  总共会创建6个  设置CELL的重用标志符  一旦可以重用就重用  不能重用再创建,减少内存的消耗。
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        static NSString *cellIdentifier = @"healthNewsTableViewCell";
        healthNewsTableViewCell *cell = [myTableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
        if (!cell) {
            cell = (healthNewsTableViewCell*)[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier: @"healthNewsTableViewCell"];
        }
        return cell;
    }
    //再将数据绑定写在WillDisPlayCell中
    //让UITableView稍微顺滑点的方法  在显示cell前被调用
    -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
        healthNewsTableViewCell *MyCell = (healthNewsTableViewCell *)cell;
        MyCell.model = dataArray[indexPath.row];
        MyCell.backgroundColor = [UIColor colorWithRed:0.936 green:0.941 blue:0.936 alpha:1.000];
        
    }
    

    19.如何使用UIScrollView实现无限加载多张图片:

    写一个NSTimer 每隔0.5秒 执行以下回调方法changPic 如果图片数量有限 进行一个if判断 当超过图片总数时候,显示第一张,重新开始从第一张显示。

    20.请简述试图控制器的生命周期:

    当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序

    1、 alloc 创建对象,分配空间
    2、init (initWithNibName) 初始化对象,初始化数据
    3、loadView 从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图
    4、viewDidLoad 载入完成,可以进行自定义数据以及动态创建其他控件
    5、viewWillAppear 视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
    6、viewDidAppear 视图已在屏幕上渲染完成

    当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反

    1、viewWillDisappear 视图将被从屏幕上移除之前执行
    2、viewDidDisappear 视图已经被从屏幕上移除,用户看不到这个视图了
    3、dealloc 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放

    21.UITableView有哪些优化方式:

    1.图片使用异步加载如SDWebImage。
    2.使用重用标识符reuseIdentifier,将重用标识标示符static NSString *CellIdentifier = @"XXX";
    3.将数据绑定写在WillDisPlay这个协议方法中。
    4.尽量在CELL中少使用不透明的View。
    5.如果不是必须,减少使用reloadData全部cell。

    22.简述IOS中的事件传递机制:

    举例:如果view是控制器的view,就传递给控制器;如不是,则将其传递给它的父视图 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理 如果window对象也不处理,则其将事件或消息传递给UIApplication对象 如果UIApplication也不能处理该事件或消息,则将其丢弃

    注意:为什么用队列管理事件,而不用栈?

    队列先进先出,能保证先产生的事件先处理。栈先进后出。

    23.UITableView有哪些必须要实现的数据源方法:

    // 获得section包含的cell个数
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; 
    //创建UITableViewCell
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    //看情况实现的数据源方法:
    //TableView中分组数目
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; 
    //分组头的标题
    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;   
    //分组尾的标题
    - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
    
    个人习惯在此方法中实现给模型绑定数据
    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    

    24.简述Http协议中get请求和post请求的区别:

    get 是从服务器获取数据 ,post是向服务器发送数据

    GET安全性较低,POST安全性较高。因为GET在传输过程,数据被放在请求的URL中,而如今现有的很多服务器、代理服务器或者用户代理都会将请求URL记录到日志文件中,然后放在某个地方,这样就可能会有一些隐私的信息被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部消息将会一同显示在用户面前。POST的所有操作对用户来说都是不可见的。

    备注:

    GET请求,将参数直接写在访问路径上。操作简单,不过容易被外界看到,安全性不高,地址最多255字节;
    POST请求,将参数放到body里面。POST请求操作相对复杂,需要将参数和地址分开,不过安全性高,参数放在body里面,不易被捕获。

    25.简述你对异步请求数据的理解:

    直白点 更好的用户体验: 减少卡顿 假死的现象。因为异步请求数据 不会一直等待某个任务完成才执行另外一个任务,可以执行其他的操作。

    26.IOS中有哪些技术可以实现开辟线程,他们之间有什么联系:
    由一个单例方法的实现推出多线程使用:

    第一种,使用@synchronized(self)
    static LocationController *sharedInstance;
    + (LocationController *)sharedInstance {
         @synchronized(self)//使用一个同步保护 保证一个线程使用时,其他线程无法进入。  
     {
         if (!sharedInstance)
         sharedInstance=[[LocationController alloc] init];
     }
     return sharedInstance;
    }
    
    第二种,使用GCD(Grand Central Dispatch:宏中心派发)
    当你调用dispatch_async,你通过一个dispatch队列,在这个队列上存有很多block,先进先出,依次执行。
    这个队列可以使用dispatch_create自己创建,也可以调用主线程队列dispatch_get_main_queue。
    这里建立的队列名称是onceToken。
    static LocationController *sharedInstance;
    + (LocationController *)sharedInstance {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            if (!sharedInstance)
                sharedInstance = [[self alloc] init];
        });
        return sharedInstance;
       }
    
    第三种,使用NSOperationQueue
    static LocationController *sharedInstance;
    + (LocationController *)sharedInstance {
        NSOperationQueue *onceToken=[[NSOperationQueue alloc] init];
        [onceToken addOperationWithBlock:^(){
          if (!sharedInstance)
                sharedInstance = [[self alloc] init];
        });
        return sharedInstance; 
        }];
        }
    

    正式列举实现单例的常用的3种方法:

    • NSThread:

    创建方式主要有两种:

    //下面为两种NSThread的创建方法:
    [NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil];
    NSThread* myThread = [[NSThread alloc] initWithTarget:selfselector:@selector(myThreadMainMethod:)object:nil];
    [myThread start]; //启动线程
    

    这两种方式的区别是:前一种一调用就会立即创建一个线程来做事情;而后一种虽然你 alloc 了也 init了,但是要直到我们手动调用 start 启动线程时才会真正去创建线程。这种延迟实现思想在很多跟资源相关的地方都有用到。后一种方式我们还可以在启动线程之前,对线程进行配置,比如设置 stack 大小,线程优先级。此外还有一种间接的方式:利用NSObject的方法performSelectorInBackground:withObject: 来创建一个线程:

    [myObj performSelectorInBackground:@selector(myThreadMainMethod) withObject:nil];
     //在后台运行某一个方法其效果与 NSThread 的 detachNewThreadSelector:toTarget:withObject: 是一样的。
    
    • NSOperationQueue (操作队列)

    @interface ViewController () {
        // 操作队列
        NSOperationQueue *queue;
    }
    @end
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 并发队列(队列中的操作会并发执行)
        queue = [[NSOperationQueue alloc] init];
        queue.maxConcurrentOperationCount = 5;
     for (int i = 0; i < 5; i++) {
            CDCar *myCar = [[CDCar alloc] initWithX:20 + 70 * i andY:10];
            [myCar draw:self.view];
              NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
                [myCar run];
            }];
            [queue addOperation:op];
        }
    }
    @end
    
    • GCD

    dispatch_async(dispatch_get_global_queue(0, 0), ^{     
    // 耗时的操作   比如网络数据数据请求
    });  
    dispatch_async(dispatch_get_main_queue(), ^{         
    // 更新界面      
     }); 
    

    27.NSThread中线程是如何实现通信的:
    28.GCD中有哪些创建线程的方式:

    dispatch_async(dispatch_get_global_queue(0, 0), ^{     
    // 耗时的操作   比如网络数据数据请求
    });  
    dispatch_async(dispatch_get_main_queue(), ^{         
    // 更新界面      
     }); 
    

    29.IOS中哪些技术可以保证线程的安全:

    1.使用互斥锁 互斥锁使用格式

    @synchronized(锁对象)
     { 
    // 需要锁定的代码 
     }
    注意:锁定1份代码只用1把锁,用多把锁是无效的
    
    • 互斥锁的优缺点
      优点:能有效防止因多线程抢夺资源造成的数据安全问题
      缺点:需要消耗大量的CPU资源
      互斥锁的使用前提:多条线程抢夺同一块资源
      相关专业术语:线程同步,多条线程按顺序地执行任务
      互斥锁,就是使用了线程同步技术

    OC在定义属性时有nonatomic和atomic两种选择
    atomic:原子属性,为setter方法加锁(默认就是atomic)
    nonatomic:非原子属性,不会为setter方法加锁

    @property (assign, atomic) int age;
     - (void)setAge:(int)age;
     {  
         @synchronized(self)
          { 
              _age = age;  
          }
     }
    
    • 原子和非原子属性的选择
      nonatomic和atomic对比
      atomic:线程安全,需要消耗大量的资源
      nonatomic:非线程安全,适合内存小的移动设备

    30.ASIHttpRequest的父类是什么:

    ASIHTTPRequest是一款极其强劲的HTTP访问开源项目。让简单的API完成复杂的功能,
    如:异步请求,队列请求,GZIP压缩,缓存,断点续传,进度跟踪,上传文件,HTTP认证。

    它是NSOperationQueues的扩展,小而强大。
    但也与它的父类略有区别。
    如,仅添加到队列中其实并不能执行请求,只有调用[queue go]才会执行;
    一个正在运行中的队列,并不需要重复调用[queue go ]。
    默认情况下,队列中的一个请求如果失败,它会取消所有未完成的请求。
    可以设置[queue setShouldCancel];
    

    31.简述AFNetWork的实现原理:

    AFNetwork是一个轻量级的网络请求api类库。是以NSURLConnection, NSOperation和其他方法为基础的。

    • AFNewWork的基本使用:
      //创建一个下载任务
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    NSURL *URL = [NSURL URLWithString:@"http://example.com/download.zip"];NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { 
    NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
     return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
    } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
     NSLog(@"File downloaded to: %@", filePath);
    }];
    [downloadTask resume];
    

    //创建一个上传任务

    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    NSURL *filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"];
    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 
    if (error) { 
    NSLog(@"Error: %@", error);
     } else { 
    NSLog(@"Success: %@ %@", response, responseObject); }
    }];
    [uploadTask resume];
    

    //带进度的上传任务

    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
     [formData appendPartWithFileURL:[NSURL fileURLWithPath:@"file://path/to/image.jpg"] name:@"file" fileName:@"filename.jpg" mimeType:@"image/jpeg" error:nil];
     } error:nil];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    NSURLSessionUploadTask *uploadTask;
    uploadTask = [manager uploadTaskWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) { 
    // This is not called back on the main queue. // You are responsible for dispatching to the main queue for UI updates dispatch_async(dispatch_get_main_queue(), ^{ 
    //Update the progress view 
    [progressView setProgress:uploadProgress.fractionCompleted]; 
    }); } completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { 
    if (error) { 
    NSLog(@"Error: %@", error);
     } else {
     NSLog(@"%@ %@", response, responseObject); 
    } }];
    [uploadTask resume];
    

    //请求数据的任务

    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    NSURL *URL = [NSURL URLWithString:@"http://httpbin.org/get"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
     if (error) { 
    NSLog(@"Error: %@", error); 
    } else { 
    NSLog(@"%@ %@", response, responseObject); 
    }}];
    [dataTask resume];
    

    32.如何理解Block,block有什么用途:

    void (^block)() = ^(){};//实质就是保存一段代码
    //定义:
    typedef void (^Block)();
    
    @property (strong,nonatomic) Block 
    

    Block是没有名字的匿名函数,类似于C语言中的函数指针。



    可以用于页面间传值 进行回调...
    举例:
    //第二个页面:

    .h
    // 定义Block类型的属性(用来保存一段回调代码)
    // 属性修饰符必须写copy因为要从栈将Block拷贝到堆上
    @property (nonatomic, copy) void(^myBlock)(NSString *);
    
    
    .m
    - (IBAction)buttonClicked:(id)sender {
       if (_myBlock) {
            // 调用Block 语法跟调用C函数是一致的
            _myBlock([NSString stringWithFormat:@"你好, %@", _nameField.text]);
        }
        [self dismissViewControllerAnimated:YES completion:^{
            NSLog(@"回到第一个视图控制器!!!");
        }];
    }
    
    

    //第一个页面 (接收页面)

    .m
    - (IBAction)buttonClicked:(UIButton *)sender {
         CDSecondViewController *secondVC = [[CDSecondViewController alloc] init];
        // 给第二个视图控制器的Block变量赋值
        secondVC.myBlock = ^(NSString *str) {
            _myLabel.text = str;
        };
        [self presentViewController:secondVC animated:YES completion:^{
            // NSLog(@"搞定第二个视图控制器!!!");
        }];
    }
    
    
    具体使用block:
    
    #import "ViewController.h"
    
    typedef void (^otherBlock) ();
    
    typedef void(^ResultBlock)(BOOL suc,NSString *plat,NSString *info);
    
    @interface ViewController ()
    
    //属性定义block
    @property (nonatomic,copy) void(^someBlock)();
    //alias定义block
    @property (nonatomic,copy) otherBlock oBlock;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
    }
    
    -(void)getDataFromServerWithResult:(otherBlock)oBlock{
        
    }
    
    -(void)getData:(ResultBlock)shareBlock{
        
    }
    
    - (void)pullDownRefreshWithFinishedCallBack:(void(^)())finishCallBack{
        
    }
    
    @end
    
    
    

    33.简述TCP和UDP的区别:

    TCP传输可靠有保证,它有三次握手机制,这一机制保证校验了数据,保证了他的可靠性。而UDP就没有了,所以不可靠。不过UDP的速度是TCP比不了的,而且UDP的反应速度更快,QQ就是用UDP协议传输的,HTTP是用TCP协议传输的。

    34.如何保证定位更省电:

    desiredAccuracy,这个属性用来控制定位精度,精度越高耗电量越高,所以应该看实际情况设置这个属性的值。

    35.简述SDWebImage的实现原理:

    • SDWebImage加载图片的流程:
    1.入口 setImageWithURL:placeholderImage:options: 会先把 placeholderImage 显示,然后 SDWebImageManager 根据 URL 开始处理图片。
    2.进入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交给 SDImageCache 从缓存查找图片是否已经下载 queryDiskCacheForKey:delegate:userInfo:。
    3.先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
    4.SDWebImageManagerDelegate 回调 webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示图片。
    5.如果内存缓存中没有,生成 NSInvocationOperation 添加到队列开始从硬盘查找图片是否已经缓存。
    6.根据 URLKey 在硬盘缓存目录下尝试读取图片文件。这一步是在 NSOperation 进行的操作,所以回主线程进行结果回调 notifyDelegate:。
    7.如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo:。进而回调展示图片。
    8.如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调 imageCache:didNotFindImageForKey:userInfo:。
    9.共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。
    10.图片下载由 NSURLConnection 来做,实现相关 delegate 来判断图片下载中、下载完成和下载失败。
    11.connection:didReceiveData: 中利用 ImageIO 做了按图片下载进度加载效果。
    12.connectionDidFinishLoading: 数据下载完成后交给 SDWebImageDecoder 做图片解码处理。
    13.图片解码处理在一个 NSOperationQueue 完成,不会拖慢主线程 UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。
    14.在主线程 notifyDelegateOnMainThreadWithInfo: 宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给 SDWebImageDownloader。
    15.imageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图片下载完成。
    16.通知所有的 downloadDelegates 下载完成,回调给需要的地方展示图片。
    17.将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。写文件到硬盘也在以单独 NSInvocationOperation 完成,避免拖慢主线程。
    18.SDImageCache 在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。
    19.SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。
    20.SDWebImagePrefetcher 可以预先下载图片,方便后续使用。
    
    

    36.简述XML和JSON数据各有哪些优势:

    (1).可读性方面。JSON和XML的数据可读性基本相同,JSON和XML的可读性可谓不相上下,一边是建议的语法,一边是规范的标签形式,XML可读性较好些。
    (2).可扩展性方面。XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,JSON不能的。
    (3).编码难度方面。XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有json.org提供的工具,但是JSON的编码明显比XML容易许多,即使不借助工具也能写出JSON的代码,可是要写好XML就不太容易了。
    (4).解码难度方面。XML的解析得考虑子节点父节点,让人头昏眼花,而JSON的解析难度几乎为0。这一点XML输的真是没话说。
    (5).流行度方面。XML已经被业界广泛的使用,而JSON才刚刚开始,但是在Ajax这个特定的领域,未来的发展一定是XML让位于JSON。到时Ajax应该变成Ajaj(Asynchronous Javascript and JSON)了。
    (6).解析手段方面。JSON和XML同样拥有丰富的解析手段。
    (7).数据体积方面。JSON相对于XML来讲,数据的体积小,传递的速度更快些。
    (8).数据交互方面。JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互
    (9).数据描述方面。JSON对数据的描述性比XML较差。
    (10).传输速度方面。JSON的速度要远远快于XML。

    37.简述线程和进程有什么联系和区别:

    看到过一篇博客 博客上面,在这里引用博客中对线程和进程的理解:

    1.计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。
    2.假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单个CPU一次只能运行一个任务。
    3.进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。
    4.一个车间里,可以有很多工人。他们协同完成一个任务。线程就好比车间里的工人。一个进程可以包括多个线程。
    5.车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。
    6.可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。
    7.一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
    8.还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。
    9.这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。
    不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。

    38.简述NSUserDefaults的使用场景和使用注意事项:

    对于NSUerdefaults来说 一般可以用来保存用户的偏好设置 比如登陆账号 密码这些。 除此之外 我们还可以用它来保存图片, 字符串 , 数字 和对象。它被保存到项目中的Plists文件里面里。保存图片 一般用它里面的两个方法 图片保存可以用PNG或者JPG对应的方法 先转换成NSData 再用NSUerdefaults保存 保存的时候为了让它马上存下来要用synchronize 。它还可以用来在程序间进行反向传值。

    39.IOS中数据库是用什么技术实现的:

    Sqlite 3

    40.简述什么是主键 什么是外键:

    主键是用来唯一确定一条记录的唯一标记,如身份证号码。外键是用来关联其他表,可以通过这个外键唯一确定另外一张表上面的字段。如:A表中有个字段是B表中的主键,那么这个字段就是A的外键。

    41.IOS中如何实现数据模型的存储:
    42.简述IOS的沙盒机制:

    IOS中的沙盒机制(SandBox)是一种安全体系,它规定了应用程序只能在为该应用创建的文件夹内读取文件,不可以访问其他地方的内容。所有的非代码文件都保存在这个地方,比如图片、声音、属性列表和文本文件等。
    1.每个应用程序都在自己的沙盒内
    2.不能随意跨越自己的沙盒去访问别的应用程序沙盒的内容
    3.应用程序向外请求或接收数据都需要经过权限认证

    43.如何实现真机调试:

    Xcode7以后可以不用配置开发者证书直接进行真机测试 嘿嘿

    44.如何查找项目中的内存泄露:

    使用Instruments来查找程序中的内存泄露,以及NSZombieEnabled。

    45.项目中支付环节如何实现的:

    注意需要配置Apple ID 其他按照微信支付或者支付宝文档进行配置

    46.如何实现项目上线到AppStore
    47.简述你在项目中遇到过哪些问题:

    以前做一个项目时,项目中使用了高德地图,当时时每点击进入一个单元格就进入地图,后来发现点击和退出的速度加快后,程序会crash。后来找了好久,发现 每次创建地图会占用很大的内存,而你每次还没有创建完毕就退出,就会导致崩溃,所以最后把创建地图的那一部分代码转移到了创建单元格哪里(前一个页面中),这样保证每次都只有一个地图。而不会因为地图还没有创建好就退出导致crash。

    48.如何实现流媒体格式的视频边播放边缓存:
    49.简述self.name = xxx 与_name=xxx的区别:

    (1)self.name 有getter 和sett er 方法
    (2)self.name 可以被kvo 监听到 (set 方法 和kvc方法)
    (3)self.name 考虑了内存管理 是一个对象指针

    前者是调用了setter方法,后者是普通的赋值。

    50.#include与#import的区别、#import与@class的区别:

    (1)#include与#import区别:#include和#import效果相同,只是后者不会引起交叉编译,确保头文件只会被导入一次。
    (2)#import和@class的区别:import会导入类的所有信息,包括变量和方法,而@class只是告诉编译器,后面的名称是类的名称。推荐使用#import,编译效率更高,防止相互包含的编译错误。

    (二)
    1.IOS中是否支持垃圾回收机制:

    IOS开发只支持手动内存管理和ARC,Mac开发支持GC垃圾回收机制,10.8之后弃用了GC,推荐使用ARC。

    2.用户自定义了一个对象,如何实现拷贝(可变和不可变拷贝)

    必须实现copying和mutableCopying协议,表示返回一个不可变和可变的对象。否则程序将会出现异常。

    -(id)copyWithZone:(NSZone*)zone{
    Person *person = [[self Class] allocWithZone:zone];
    person->age = self.age;
    person->name = self.name;
    return person;
    }
    
    -(id)mutableCopyWithZone(NSZone*)zone;
    

    3.释放对象的时候为什么要调用[super dealloc]:

    因为子类继承父类,子类中一些对象(实例变量)也是继承父类的,因此我们需要调用父类的方法,将父类所拥有的实例进行释放。

    4.简述常见的设计模式:

    单例设计、代理设计、观察者(通知)、工厂方法。

    5.内存管理中使用release方法好还是使用self.xxx = nil好:

    使用self.xxx = nil 好,因为它会先调用release方法,而且将变量设置为nil,这样就可以更安全的释放对象,防止野指针调用。

    6.事件响应者链的概念:

    响应者链表示一系列的响应者对象。事件被交给第一响应者处理,如果第一响应者不处理,事件会沿着响应者链条向上传递,交给下一个响应者(next responder)。一般来说第一响应者是个视图或者其子类对象,当其被触摸后事件交给它处理,如果不处理,事件就会被传递到它的视图控制器(如果存在),然后是它的父视图(superview)(如果存在),以此类推,直到顶层视图。接下来会沿着顶层视图(top view)到窗口(UIWindow)再到UIApplication。如果整个过程都没有响应这个事件,该事件就会被丢弃。

    7.static变量和static函数的区别:

    (1)static变量表示静态存储变量,变量存储在静态存储区。
    (2)加在函数前面表示该函数是内部连接,只在本文件中有效,别的文件中不能应用该函数。

    static 全局变量与普通的全局变量有什么区别:static 全局变量只初使化一次,
    防止在其他文件单元中被引用;
    static 局部变量和普通局部变量有什么区别:static 局部变量只被初始化一次,
    下一次依据上一次结果值;
    static 函数与普通函数有什么区别:static 函数在内存中只有一份,普通函数
    在每个被调用中维持一份拷贝

    8.面向对象的三大支柱 以及如何理解动态绑定(多态):

    三大支柱:封装、多态、继承
    多态:
    继承父类,实现方法,只看对象不看指针,不同的对象实现自己重写的不同的方法。

    9.frame与bounds的区别:

    (1)Frame:该view是在父view坐标系中的位置和大小(参照点是父视图的坐标系)当view做了transform时,该值不准确。
    (2)Bounds:该view是在本身坐标系的位置和大小(参照点是本身的坐标系统)。

    10.谈谈对Runloop的理解:

    Run loop是线程相关的基础框架的一部分。一个run loop就是一个事件处理的循环,用来不停的调度工作以及处理输入事件。使用run loop的目的就是让你的线程在有工作的时候忙起来,没有工作的时候休眠。

    11.SVN、Git协作开发,怎样防止代码文件冲突:

    (1)防止代码冲突:不要同时多人修改同一个文件。例如A、B都同时修改一个文件,先让A修改,然后提交到服务器,然后B更新下来,在进行修改。
    (2)服务器上的项目文件xcodeproj,仅让一个人管理提交,其他人只更新。防止此文件产生冲突。

    12.断点续传如何实现的:

    将下载的文件分成几个部分,通过http协议的请求头,设置每一部分下载的偏移量,然后通过多线程下载每一部分,下载完成以后 再组成为最终的完整文件。

    13.堆和栈的区别 以及队列和栈的区别:

    栈区(stack)由编译器自动分配释放,存放 方法(函数)的参数值、局部变量的值等、堆区(heap)一般由程序员分配和释放、若不释放,则内存溢出。
    队列:先进先出 栈:先进后出

    14.协议、代理的理解:

    实际上是两个对象的相互调用
    A类 B类 A中有B的对象 B.delegate=A

    15.HTTP协议、TCP、UDP协议

    数据请求:状态行、请求头、请求体
    服务端响应:响应头(状态码:200;404资源没有找到;400客户端请求语法错误;500服务器错误;)响应体w3c school在线教程

    16.IOS 6 与 IOS 7区别:

    IOS 6 拟物化风格
    IOS 7 扁平化风格

    17.什么是指针:

    type *p;
    type:类数据类型。用来存储内存单元的编号指针 不完全等于 地址!有类型的标识很多类型的指针,指向数据、指向方法、void 型 。不同的编译环境,sizeof 可能不同。

    18.写一个宏,输入两个参数返回其中较小的一个:

    #define MIN(a,b) ((a)>(b)?(b):(a))
    

    19.排序算法:

    选择排序

    
    -(void)bunbleSort:(NSMutableArray *)aData{
    int count = 0;
    for(int i = 0; i < [aData count]-1;i++)
    {
    for(int j = i+1; j < [aData count];j++)
    {
    if([[aData objectAtIndex:i] integerValue] < [[aDataobjectAtIndex:j]integerValue])
    {
    NSNumber *temp = [aData objectAtIndex:i];
    [aData replaceObjectAtIndex:i withObject:[aData
    objectAtIndex:j]];
    [aData replaceObjectAtIndex:j withObject:temp];
    count ++;}
    }}
    }
    

    冒泡排序

    
    -(void)sort2:(NSMutableArray *)resource{
    //NSNumber小 -> 大
    int count = [resource count];
    for(int i = 0; i < count-1; i ++)
    {
    for(int j = 0; j < count-i-1; j ++)
    {
    if([[resource objectAtIndex:j] integerValue]>[[resource objectAtIndex:j+1] integerValue])
    {
    NSNumber *temp = [resource objectAtIndex:j];
    [resource replaceObjectAtIndex:j
    withObject:[resource objectAtIndex:j+1]];
    [resource replaceObjectAtIndex:j+1
    withObject:temp];
    }
    }}
    }
    

    快速排序

    
    -(void)quickSortWithArray:(NSMutableArray *)aDataleft:(NSInteger)left right:(NSInteger)right
    {
    if (right > left) {NSInteger i = left;
    NSInteger j = right + 1;
    while (true) {
    while (i+1 < [aData count] && [aData objectAtIndex:++i] <[aData objectAtIndex:left]) ;
    while (j-1 > -1 && [aData objectAtIndex:--j] > [aDataobjectAtIndex:left]) ;
    if (i >= j) 
    {
    break;
    }
    [self swapWithData:aData index1:i index2:j];
    }
    [self swapWithData:aData index1:left index2:j];
    
    [self quickSortWithArray:aData left:left right:j-1];
    [self quickSortWithArray:aData left:j+1 right:right];
    }
    }
    -(void)swapWithData:(NSMutableArray *)aDataindex1:(NSInteger)index1 index2:(NSInteger)index2
    {
    NSNumber *tmp = [aData objectAtIndex:index1];
    [aData replaceObjectAtIndex:index1 withObject:[aDataobjectAtIndex:index2]];
    [aData replaceObjectAtIndex:index2 withObject:tmp];
    }
    

    20.写一个单链表,要求可以插入数据和删除单个数据:

    
    struct QFInfo{
    int num;
    struct QFInfo *next;
    };
    struct QFInfo *qfinfo;
    //链表头
    void insert_AtFirst(struct QFInfo *head,struct QFInfo *insert)
    {
    insert->next = head->next;
    head->next = insert;
    }
    //链表尾
    void insert_AtEnd(struct QFInfo *head,struct QFInfo *insert)
    {
    struct QFInfo *temp = head->next;
    while (temp->next != NULL) {
    temp = temp->next;
    }
    insert->next = NULL;
    temp->next = insert;
    }
    //删除
    void delete_1(struct QFInfo *head,struct QFInfo *del)
    {
    struct QFInfo *temp = head->next;
    while (temp->next != NULL && temp->next != del)
     {
    temp = temp->next;
    }
    if(temp->next != NULL)
    {
    temp->next = temp->next->next;
    }
    }
    

    21.下面的程序中,3次retainCount分别是什么,为什么:

    NSMutableArray *arr = [[NSMutableArray array] retain]; 
    NSString *str = [NSString stringWithFormat:@"test"];
     [str retain]; 
    [arr addObject:str]; 
    NSLog(@"%@%lu",str,[str retainCount]); 
    [str retain]; 
    [str release]; 
    [str release]; 
    NSLog(@"%@%lu",str,[str retainCount]);
     [arr removeObject:str];
     NSLog(@"%@%lu",str,[str retainCount]);
    分别是3、2、1,因为初始化的时候retain  为1,retain的时候+1,往数组中add的时候+1,release的时候-1,从数组中删除的时候-1。
    

    22.引用和指针的区别:

    1 .从现象上看:指针在运行时可以改变其所指向的值,而引用一旦和某个对象绑定后就不再改变。引用访问一个变量是直接访问,而指针是间接访问。
    2.从内存分配上看:程序为指针变量分配内存区域,而引用不分配内存区域。
    3.从编译上看:程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变指向的对象(指针变量中的值可以改),而引用对象不能改。

    23.如何将图片添加到相册:

    
    UIImage *img = [UIImage imageWithNamed:@”123.ppng”];
     UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);
    

    24.写一个获取日期的方法,输出格式为2016-08-08:

    
    NSDate *date = [NSDate date];
    NSDateFormatter *dateFm = [[NSDateFormatter alloc] init];
     dateFm.dateFormat = @"yyyy-MM-dd"; 
    NSString *dateStr = [dateFm stringFromDate:date];
    NSLog(@"dateStr:%@",dateStr);
    

    25.将一组数据永久保存到手机里:

    NSUserDefaults、plist、数据库、普通文件、归档

    26.NSarray *array = @[@“a”,@“b”,@“c”,@“a”,@“d”....],里面有N个string元素,求出array中唯一元素,要求复杂度为N:

    (分析:将重复的元素去掉拼接成一个字符串)
    代码实例:
    NSArray *arr = @[@"a",@"b",@"b",@"c"];
    NSString *resultStr = [arr objectAtIndex:0];
    for (NSString *str in arr) 
    {
    if ([resultStr rangeOfString:str].location == NSNotFound) {
    resultStr = [resultStr stringByAppendingString:str];
    }
    }
    NSLog(@"%@",resultStr);
    

    27.写一个Block使用的例子,尽可能体现出block编程的语法和优势:

    void(^myBlock)(NSString *msg);
    myBlock = ^(NSString *str){
    NSLog(@"%@",str);//line3
    }
    //使用block
    //相当于把line3的代码放在这里执行。
    myBlock(@"hello!");
    

    28.nil和NULL有什么区别:

    nil是一个对象,NULL是一个值

    29.什么时候使用NSMutableArray,什么时候使用NSArray:

    当数组在程序运行时,需要不断变化的,使用NSMutableArray,当数组在初始化后,便不再改变的,使用NSArray。需要指出的是,使用NSArray只表明的是该数组在运行时不发生改变,即不能往NSAarry的数组里新增和删除元素,但不表明其数组內的元素的内容不能发生改变。NSArray是线程安全的,NSMutableArray不是线程安全的,多线程使用到NSMutableArray需要注意。

    30.如果我们不创建内存池,是否有内存池提供给我们:

    界面线程维护自己的内存池,用户自己创建的数据线程,则需要创建该线程的内存池。

    31.类NSObject的那些方法经常被使用:

    NSObject是Objetive-C的基类,其由NSObject类及一系列协议构成。
    其中类方法alloc、class、description 对象方法init、dealloc、– performSelector:withObject:afterDelay:等经常被使用。

    32.什么是谓词:

    谓词是通过NSPredicate,是通过给定的逻辑条件作为约束条件,完成对数据的筛选。
    predicate = [NSPredicate predicateWithFormat:@"customerID == %d",n];
    a = [customers filteredArrayUsingPredicate:predicate];
    

    33.简述内存分区情况:

    1).代码区:存放函数二进制代码
    2).数据区:系统运行时申请内存并初始化,系统退出时由系统释放。存放全局变量、静态变量、常量
    3).堆区:通过malloc等函数或new等操作符动态申请得到,需程序员手动申请和释放
    4).栈区:函数模块内申请,函数结束时由系统自动释放。存放局部变量、函数参数

    相关文章

      网友评论

      • 7d0e5c9e8949:总结的太好了,最近找工作正好用的着,
      • 神采飞扬_2015:category只能添加属性;这什么鬼?
        Hither:@神采飞扬_2015 都可以添加
      • 神采飞扬_2015:误人子弟:#define MIN(a,b) ((a)>(b)?(b):(a)),这种写法!
        Hither:@神采飞扬_2015 请你 测试了 以后 再来评论 正确与否 我放在上面的 都是经过自己测试 检验 才放上去的 不会乱放东西 去误导别人
        Hither:@神采飞扬_2015 正规的写法 需要加上 括号 我这样写 没错 你写的时候不加括号 那是你自己的习惯
        Hither:@神采飞扬_2015 请问 我这种写法 哪里错了???
      • 如风家的秘密:category 不是只能添加方法,不能添加属性吗?
        Hither:@如风家的秘密 通过runtime可以完成你想做的
      • piaoxu:very good
      • PPAbner:目前看到的最想要的一份!!!
        Hither: @PP_Abner 别停
        PPAbner:@hither 好的!哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇
        Hither: @PP_Abner 拿走 不谢
      • 43aedd85acb8:好
        Hither: @43aedd85acb8 一起学习
      • lizhi_boy:总结得很全面,大赞!!!! :+1:
        Hither: @荔枝_boy 一起进步!
      • 嚤仌啾啾:不错哈
        Hither:@嚤仌啾啾 共同学习~
      • Cyandev:很全啊,不错
        Hither:@Cyandev 共同学习
      • c09a3b25e5c1:确定不是某大学考试题?
        Hither: @ZGMF_X42S 不是的哈

      本文标题:IOS面试

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