iOS 笔试题

转:http://blog.sina.com.cn/s/blog_b0c5954101014upb.html

 

1.截取字符串”20|http://www.621life.com“ 中 ‘|’字符前面及后面的数据,分别输出它们

NSRange range = [responseString rangeOfString:@"|"];
int location = range.location;
NSString *str1 = [responseString substringToIndex:location];
NSString *str2 = [responseString substringFromIndex:location+1];

2.获取项目根路径,并在其下创建一个名称为userData的目录。

// 路径
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    
    NSString *documentsDirectory = [paths firstObject];
    
    NSFileManager *fileManager = [[NSFileManager alloc]init];
    
    NSString *userDataPath = [NSString stringWithFormat:@"%@/userData",documentsDirectory];
    if (![fileManager fileExistsAtPath:userDataPath]) {
        [fileManager createDirectoryAtPath:userDataPath withIntermediateDirectories:false attributes:nil error:nil];
    }

3.在一个对象的方法里面:self.name = “object”;和name =”object”有什么不同吗?

self.name = “object”会调用对象的setName()方法,
name = “object”会直接把object赋值给当前对象的name 属性。
并且 self.name 这样retainCount会加1,而name就不会。

4.定义属性时,什么情况使用copy,assign,和retain

assign用于简单数据类型,如NSInteger,double,bool,retain 和copy用户对象;

copy用于当 a指向一个对象,b也想指向同样的对象的时候,如果用assign,a如果释放,再调用b会crash,如果用copy 的方式,a和b各自有自己的内存,就可以解决这个问题。

retain 会使计数器加一,也可以解决assign的问题。

另外:tomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。

5.关键字const有什么含意?修饰类呢?static的作用,用于类呢?还有extern c的作用

前两个的作用是一样,a是一个常整型数。

第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。

第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。

最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。

结论:

 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。

 如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让

 别人 来清理的。)   通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。  


 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug

 的出  现。  
 

(1)欲阻止一个变量被改变,可以使用 const 关键字。在定义该 const 变量时,通常需要对它进行初
始化,因为以后就没有机会再去改变它了;
(2)对指针来说,可以指定指针本身为 const,也可以指定指针所指的数据为 const,或二者同时指
定为 const;
(3)在一个函数声明中,const 可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
(4)对于类的成员函数,若指定其为 const 类型,则表明其是一个常函数,不能修改类的成员变量;
(5)对于类的成员函数,有时候必须指定其返回值为 const 类型,以使得其返回值不为“左值”。

关键字volatile有什么含意?并给出三个不同的例子。

一个定义为 volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。

精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

下面是volatile变量的几个例子:

并行设备的硬件寄存器(如:状态寄存器)  
 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)  
 多线程应用中被几个任务共享的变量


 一个参数既可以是const还可以是volatile吗?解释为什么。  
 一个指针可以是volatile 吗?解释为什么。

下面是答案:  
 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。  
 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。

6. static 关键字的作用:

(1)函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次,
因此其值在下次调用时仍维持上次的值;
(2)在模块内的 static 全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
(3)在模块内的 static 函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明
它的模块内;
(4)在类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
(5)在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的static 成员变量。

 extern "C" 的作用

(1)被 extern "C"限定的函数或变量是 extern 类型的;
     extern 是 C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,
     其声明的函数和变量可以在本模块或其它模块中使用。

(2)被 extern "C"修饰的变量和函数是按照 C 语言方式编译和连接的;
 extern "C"的惯用法

(1)在 C++中引用 C 语言中的函数和变量,在包含 C 语言头文件(假设为 cExample.h)时,需进
       行下列处理:
  extern "C"  {  
   #include "cExample.h"  
  }  
而在 C 语言的头文件中,对其外部函数只能指定为 extern 类型,C 语言中不支持 extern "C"声明,
在.c 文件中包含了 extern "C"时会出现编译语法错误。

(2)在 C 中引用 C++语言中的函数和变量时,C++的头文件需添加 extern "C",但是在 C 语言中不
能直接引用声明了 extern "C"的该头文件,应该仅将 C 文件中将 C++中定义的 extern "C"函数声明为
extern 类型。

7.readwrite,readonly,assign,retain,copy,nonatomic 属性的作用

@property是一个属性访问声明,扩号内支持以下几个属性:
1,getter=getterName,setter=setterName,设置setter与 getter的方法名
2,readwrite,readonly,设置可供访问级别
2,assign,setter方法直接赋值,不进行任何retain操作,为了解决原类型与环循引用问题
3,retain,setter方法对参数进行release旧值再retain新值,所有实现都是这个顺序(CC上有相关资料)
4,copy,setter方法进行Copy操作,与retain处理流程一样,先旧值release,再 Copy出新的对象,retainCount为1。

   这是为了减少对上下文的依赖而引入的机制。
5,nonatomic,非原子性访问,不加同步,多线程并发访问会提高性能。注意,如果不加此属性,则默认是两个访问方法

   都为原子型事务访问。锁被加到所属对象实例级(我是这么理解的...)。

33.线程的常见方法有哪些,你是如何处理多线程的,多线程同步问题你了解么?
线程创建的几种方式,线程的加锁,休眠,唤醒,解锁,退出,

多线程要考虑同步问题,解决同步问题的方式就是对某一资源加锁,当一个线程操作本资源时,其他线程不能操作 。

 
系统自带线程池(NSOpertionQueue)的作用:

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

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

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

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

而NSOpertionQueue可以很好的处理他。

34.init和initwithobject区别(语法)?

   init创建的对象不带自动释放

35.你连接服务器用的是什么方法,如果请求过程中,网络出了问题这么办?
NSUrlConnection 连接后,有一系列委托方法来接受来自服务器的响应和数据,

其中接受相应的方法回得到服务器要传回的数据有多大,接受数据的方法会反复调用来不断接受服务器数据,

如果网络出了问题了,会调用一个方法让你来做相关处理。


36.你使用过json解析方式么,他们的底层是如何处理的你了解么?


json解析的用法,用框架的用法简单介绍:

底层原理遍历字符串中的字符,最终根据格式规定的特殊字符,比如{}号,[]号, : 号 等进行区分,

 {}号是一个字典的开始,[]号是一个数组的开始, : 号是字典的键和值的分水岭,最终乃是将json数据转化为字典,

字典中值可能是字典,数组,或字符串而已。

37.xml解析的原理是什么,你还用过其他解析方式么?

NSXMLParser, 其他解析方式有自定义二进制解析,就是按字节去解析,电话会谈就是如此,

还可以是字符串之间用特殊符号连接的数据,将此数据用特殊符号可以分割成所用数据。

38.协议是什么,有什么作用.?


协议很像java中的接口,某个类实现协议后,就必须实现协议中规定的@require的方法,比如一个类A, 一个类B都实现某“协议”后,

这个类A的对象和B的对象都可以赋值给这个协议的类型变量,比如  id<协议> 变量名 = A类或B类的对象,

于是这个变量就完成了能够指向多个不同的类的对象并调用对象中的实现协议的方法。

39.类别有什么作用?
类别的使用 。 类别有三大作用,

1. 可以使本来需要在.h中声明的方法放到.m文件中声明,达到了可以使方法不对外公开。

2. 可以方便的扩展类,甚至系统类都可以轻易扩展,维护了代码原本的结构不受影响。

3. 类别可以写到不同的.h或.m文件中,可以分散代码到跟类别的扩展功能想关联的地方,方便查看。

40.分线程回调主线程方法是什么,有什么作用?
[self    performSelectorOnMainThread:@selector(buttonGo2) withObject:nil waitUntilDone:YES];
[self performSelector:@selector(buttonGo2) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];
需要即时刷新ui控件的时候,经常使用。


41.iphone阅读器,如果要读取一个文本文件,请问你是如何处理编码问题的?另外像pdf格式的文件,你如何读取。?


iphone手机阅读器中对于PDF格式的阅读,可以直接用UIWebView控件显示,也可以从网上下到很多直接读取pdf格式的代码

直接从pdf中得到数据。

复杂表格动画
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation; -(void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;

42.你在开发大型项目的时候,如何进行内存泄露检测的?
  可以通过xcode的自带工具run---start with performance tool里有instruments下有个leaks工具,

  启动此工具后,运行项目,工具里可以显示内存泄露的情况,双击可找到源码位置,可以帮助进行内存泄露的处理。

43.你做iphone开发时候,有哪些传值方式,view和view之间是如何传值的?

     压栈。

44.让一个物体从界面中的一点运动到另外一点,有哪些方法?
四种方式:1. beginAnimation

              2. 线程

              3. NSTimer

              4. 图层动画(路径)


45.你了解哪些加密方式?
   Base64, MD5, 循环右移位等.

46.地图定位

CLLocationManager位置管理器  使用Core Location框架来确定iphone的位置(GPS,蜂窝基站三角网,wps三种方式)    

MKMapView提供了一套可植入的地图接口,可以让我们在应用中展示地图,并对其进行相关的操作。一般来说,我们可以指定一个展示区域,放一些标记在上面,还可以加盖一些层在上面。

MKMapView依赖Google map里面相关服务(如Google Earth API等),所以地图的左下角会有Google字样。

47.打开url

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://8004664411"]];mailto://   sms://

48. http网络通信

ASIHTTPRequest 是一个直接在CFNetwork上做的开源项目:提供直接提交(HTTP POST)文件的API,异步请求与队列,自动管理上传与下载队列管理机,ASIFormDataRequest用于适合上传文件,图片数据。

49. 图片浏览

UIImagePickerController可以从相册,相机,胶卷里获得图片。

50. 对像序列化

NSCoding    encodeWithCoder   initWithCoder

NSKeyedUnarchiver   NSKeyedArchiver

51. 各种picker

UIDatePicker   UIPickerView

52. 电影播放

     MPMoviePlayerController

     音乐播放

     MPMusicPlayerController

53.线程 ?

      a. 线程的创建和使用规则?

         答:NSThread

                 三种方法

                - (id)init; // designated initializer

                - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;

                + (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument

                 - (void)start;

       b. 主分线程

          答:启动分线程,上面已提到!加到主线程方法performSelector!

          //加到主线程addData()是主线程的方法!只有加到主线程后,才能调用主线程的方法

         [target performSelector:@selector(addData:) onThread:[NSThread mainThread] withObject:item waitUntilDone:YES];

           //[target addData:item];//没有加到主线程后,调用主线程的方法!一定会崩!

      c.线程锁

         答:NSCondition

                 方法:

                 [thread lock];//加锁

                 sleep(n);//线程休眠

                 [thread singnal];//相当于通知,线程启动

                 [thread unlock];//解锁

                 [thread exit];//线程退出

54.各种 排序算法?

     希尔排序、快速排序、冒泡排序、

55.通信底层原理

    答:OSI七层模型

    7 应用层:    ftp,smtp,http,telnet,tftp(通过各种协议,最终还是包装成TCP数据包,发送到网络中!)

    6 表现层:

    5 会话层:

    4 传输层:    tcp udp

    3 网络层:    ip,ICMP,IGRP,EIGRP,OSPF,ARP

    2 数据链路层: STP,VT

    1 物理层:

56. 为什么很多内置类如UITableViewController的delegate属性都是assign而不是retain的?

答:

      会引起循环引用

      所有的引用计数系统,都存在循环应用的问题。例如下面的引用关系:

          * 对象a创建并引用到了对象b.

          * 对象b创建并引用到了对象c.

          * 对象c创建并引用到了对象b.

      这时候b和c的引用计数分别是2和1。

      当a不再使用b,调用release释放对b的所有权,因为c还引用了b,所以b的引用计数为1,b不会被释放。

      b不释放,c的引用计数就是1,c也不会被释放。从此,b和c永远留在内存中。

这种情况,必须打断循环引用,通过其他规则来维护引用关系。我们常见的delegate往往是assign方式的属性而不是retain方式 的属性,

赋值不会增加引用计数,就是为了防止delegation两端产生不必要的循环引用。

如果一个UITableViewController 对象a通过retain获取了UITableView对象b的所有权,这个UITableView对象b的delegate又是a,

如果这个delegate是retain方式的,那基本上就没有机会释放这两个对象了。自己在设计使用delegate模式时,也要注意这点。

57. 以下每行代码执行后,person对象的retain count分别是多少?

      Person *person = [[Person alloc] init]; count 1

      [person retain]; retain  count 2

      [person release];retain count 1

      [person release];retain count = 0

58.在一个对象的方法里面:

      self.name = “object”;

      和

      name =”object”

      有什么不同吗?  

答:self.name = "object"会调用对象的setName()方法,会使object引用计数加1,name = "object"会直接把object赋值给当前对象的name 属性,引用计数不增加。


59.readwrite,readonly,assign,retain,copy,nonatomic属性的作用?

@property是一个属性访问声明,扩号内支持以下几个属性:
1,getter=getterName,setter=setterName,设置setter与getter的方法名
2,readwrite,readonly,设置可供访问级别


3,assign,setter方法直接赋值,不进行任何retain操作,为了解决原类型与环循引用问题
4,retain,setter方法对参数进行release旧值再retain新值,所有实现都是这个顺序(CC上有相关资料)


5,copy,setter方法进行Copy操作,与retain处理流程一样,先旧值release,再Copy出新的对象,retainCount为1。这是为了减少对上下文的依赖而引入的机制。


6,nonatomic,非原子性访问,不加同步,多线程并发访问会提高性能。注意,如果不加此属性,则默认是两个访问方法都为原子型事务访问。锁被加到所属对象实例级(我是这么理解的…)。

7,@synthesize xxx; 来实现实际代码



60.1.main()

 {

   int a[5]={1,2,3,4,5};

   int *ptr=(int *)(&a+1);

   printf("%d,%d",*(a+1),*(ptr-1));

}

答:2,5

     *(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5
  &a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)
  int *ptr=(int *)(&a+1);
  则ptr实际是&(a[5]),也就是a+5
原因如下:

  &a是数组指针,其类型为 int (*)[5];
  而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同。
  a是长度为5的int数组指针,所以要加 5*sizeof(int)
  所以ptr实际是a[5]
  但是prt与(&a+1)类型是不一样的(这点很重要)
  所以prt-1只会减去sizeof(int*)

    a,&a的地址是一样的,但意思不一样
     a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,
     a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].

原文地址:https://www.cnblogs.com/lihaibo-Leao/p/4618261.html