最近参加了一些面试,总结一些IOS开发的基础点。
1.保留计数的问题:
保留计数主要是在非ARC模式下需要特别的注意,当然这里并不是说ARC模式下就没有保留计数,只是在ARC模式下 ,编译器LLVM会
自动插入release,实现内存管理。OC的内存控制根据属性关键字的不同,控制方式不同。
这里分析下assign,retain和copy的区别。
NSString *str = [[NSString alloc]initWithString:@"abc"];
这句话产生的动作:(1)在堆上分配一块内存,存@“abc”,如地址0X111,内容为“abc”;
(2)在栈上分配一块内存,如地址0XAAA,内容为0X111;
(1)NSString *newStr = [str assign];
此处newStr和str完全相同,地址0XAAA,内容为0X111,因此retainCount不需要增加;
(2)NSString *newStr = [str retain];
此处在栈上可能重新分配了地址,但是内容仍未0X111,所以次数有新的指针指向了装“abc”的地址,retainCount+1;
(3)NSString *newStr = [str copy];
此处在堆上会重新开辟地址存放“abc”,如地址0X222,内容为“abc”;栈上有伟newStr重新分配空间,如0XCCC,retainCount+1供newStr管理0X222内存。
注意,当用alloc,new,create和copy构建一个对象,则须承担释放对象的任务。
2.类别category:扩展已经存在的类的内置功能,这种行为性扩展就叫类别。
格式:@interface NSString(NumberConvenience)
-(NSNumber*) lengthAsNumber;
@end
3.协议delegate:协议定义了一个类和另一个类沟通的先验方式,它包含了一个方法列表,有的事可选的,有的事必须的。协议中定义的方法包括了一些操作响应和
时间响应。委托和数据源都是有协议的系统产生的。
4.消息:主要是弥补不提供真正多继承而设计的方法。
要实现消息转发,必须覆盖methodSignatureForSelector和forwardInvocation。
5.NSBundle类:
bundle是一个目录,包含了程序会使用到的资源,NSBundle *myBundle = [NSBundle mainBundle];得到bundle后就能用资源了。
6.多线程使用有三种方法:NSThread、NSOperation、GCD
7.一个工程的几种状态:
- (void)applicationWillResignActive:(UIApplication *)application
说明:当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件,比如来电话了;
- (void)applicationDidBecomeActive:(UIApplication *)application
说明:当应用程序入活动状态执行,这个刚好跟上面那个方法相反
- (void)applicationDidEnterBackground:(UIApplication *)application
说明:当程序被推送到后台的时候调用。所以要设置后台继续运行,则在这个函数里面设置即可
- (void)applicationWillEnterForeground:(UIApplication *)application
说明:当程序从后台将要重新回到前台时候调用,这个刚好跟上面的那个方法相反。
- (void)applicationWillTerminate:(UIApplication *)application
说明:当程序将要退出时被调用,通常是用来保存数据和一些退出前的清理工作。这个需要要设置UIApplicationExitsOnSuspend的键值。- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
说明:iPhone设备只有有限的内存,如果为应用程序分配了太多内存操作系统会终止应用程序的运行,在终止前会执行这个方法,通常可以在这里进行内存清理工作防止程序被终止
- (void)applicationSignificantTimeChange:(UIApplication*)application
说明:当系统时间发生改变时执行
- (void)applicationDidFinishLaunching:(UIApplication*)application
说明:当程序载入后执行
- (void)application:(UIApplication)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
说明:当StatusBar框将要变化时执行
- (void)application:(UIApplication*)application willChangeStatusBarOrientation: (UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration 说明:当StatusBar框方向将要变化时执行
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url
说明:当通过url执行
- (void)application:(UIApplication*)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
说明:当StatusBar框方向变化完成后执行
- (void)application:(UIApplication*)application didChangeSetStatusBarFrame:(CGRect)oldStatusBarFrame
说明:当StatusBar框变化完成后执行
8.block使用时,注意只能读取外部变量,如果要修改的话,需要用__block来修饰外部变量。
9.Objective-C 中 #import , #include 和@class的区别 :
#import由gcc编译器支持的,相比于#include,#import不会引起交叉编译。@class就是告诉编译器有这么一个类,@class一般用于头文件中需要声明该类的某个实例变量的时候用到,在m文件中还是需要使用#import
10.c和obj-c如何混用,C++和obj-c呢
obj-c的编译器处理后缀为m的文件时,可以识别obj-c和c的代码,处理mm文件可以识别obj-c,c,c++代码,但cpp文件必须只能用c/c++代码,而且cpp文件include的头文件中,也不能出现obj-c的代码,因为cpp只是cpp;
11.self.name = “a”; 和 name =”a”的区别:前者会先调用set方法,在赋值,而后者直接赋值给当前对象;
12.@interface和@property的区别:
@interface申明了一个类,而@property是属性生成器,其实本质就是申明了set和get方法;
13.自动释放池是什么,如何工作?
当您向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放池。它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池就会被释放,池中的所有对象也就被释放。
14.分清一位数组中a和&a的区别:
比如有数组:int a[5]={1,2,3,4,5}; 则此时a指的是此一维数组的首元素a[0],而&a是此对象的首地址,本例也是a[0]。但是a+1是a[1],&a+1是下一个对象的地址,本例中就应该是a[5]了;
15 #define 语法的基本知识(例如:不能以分号结束);
16 objective-c -类里面的方法只有两种, 静态方法和实例方法,没有所谓的私有方法,当然有私有属性(private修饰);
17.书写一个单例类的Book(手写)
单例模式的意思就是确保某一个类只有一个实例,而且自行实例化,并向整个系统提供这个实例。这个类就称为单例类。
OC中实现单例,至少需要四个步骤:
1为单例对象实现一个静态实例,并初始化,然后设置成nil,
2实现一个实例构造方法检查上面声明的静态实例是否为nil,如果是则新建并返回一个本类的实例,
3重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实例的时候不产生一个新实例,
4适当实现allocWitheZone,copyWithZone,release和autorelease。
代码实现:
static Book *book = nil;//第一步:静态实例,并初始化
@implementation Book
+(Book *)shareBook //第二步:实力构造检查静态实例是否为nil
{
@synchronized(self)
{
if(book == nil)
{
[[self alloc]init];
}
}
return book;
}
+(id)allocWithZone:(NSZone *)zone//第三步:重写allocWithZone方法
{
@synchronized(self){
if(book == nil){
book = [superallocWith Zone:zone];
return book;
}
}
return nil;
}
-(id)copyWithZone: (NSZone *)zone//第四步:适当实现相应方法
{
return self;
}
18 举例说两个动态调用有关的方法:respondsToSelector、perforSelector;
19 程序查错
ClassA *class1 = [[ClassA alloc]init];
ClassA *class2 = class1;
[class1 hello];
[class1 release];
[class2 hello];(2)
[class2 release];
问能执行到(2)步吗?不能的话,怎么改?
不能执行到,因为class1和class2都指向同一个对象,class1执行release方法后,class2就成了无效指针。修改:
ClassA *class1 = [[ClassA alloc]init];
ClassA *class2 = class1;
[class2 retain];
[class1 hello];
[class1 release];
[class2 hello];
[class2 release];
20 用OC实现冒泡法 - (NSArray *)bubble_sort:(NSArray *)array
{
int tmp;
int count = [array count];
//获得临时数组应该有的长度
int *tmpArray = (int *)malloc(sizeof(int)*count);
if (tmpArray == NULL) {
printf("malloc error");
return nil;
}
//把oc对象数组里的内容暂时存放到临时数组里
for (int i = 0; i < count; i++) {
tmpArray[i] = [[array objectAtIndex:i] intValue];
}
//冒泡排序过程
for (int i = 0; i < count-1; i++) {
for (int j = 0; j < count-1-j; j++) {
if (tmpArray[j] > tmpArray[j+1]) {
tmp = tmpArray[j];
tmpArray[j] = tmpArray[j+1];
tmpArray[j+1] = tmp;
}
}
}
//最后把排序后的结果回写到oc对象数组里。
NSMutableArray *results = [NSMutableArray array];
for (int i = 0; i < count; i++) {
[results addObject:[NSNumber numberWithInt:tmpArray[i]]];
}
//释放临时数组空间
free(tmpArray);
//返回结果
return [NSArray arrayWithArray:results];
}