Objective-c学习笔记-基础版
1. xcode 4.3.3以后 NSAutoreleasePool 的用法发生改变,由
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
….
[pool drain];
变为:
@autoreleasepool {
….
}
2. 在objc中也存在static 关键字,作用与Java中的static 相同即, 内存中只有一份。For example:
类Maths_, 其中有一个属性是 static int number(初始化为 0 ), 类方法使number++,然后new了10个Maths_类, 每个类都调用类方法使number++,看最后结果。
正常,每个类的number属性是独立的,若加上static 因为内存中只有一份,所以10个类操作的都是同一个number.
3. self 关键字作用同Java中的this相同,即谁调用谁就是self/this.
4. 在方法中如果用了new/[~ alloc]分配内存,就要在方法的结尾手动的释(release)内存.
5. objc中的继承我个人称之为向上继承,即,子类可以向上继承所有父类,父类的父类的属性和方法。
6. @class A和#import "A.h"两种方法注入类时 ,有什么区别?
答:@class只是告诉当前类, A是一个类,并不用处理。(效率高,因为只注入类名)
#import "A.h" 是把整个A类注入到当前类中。(相对是@class效率低,因为把整个类注入)
那么什么时候用@class A ,什么时候用#import "A.h"呢?
答:当前类没有调用任何A类的方法和属性的时候,无需用#import.
继承的时候,必须用#import
7. 如何在当前类中,释放继承的类所占的内存:
答: 重写dealloc方法
- (void) dealloc {
[super dealloc];
// [~ release];
...
}
8. objc特征 :多态,动态类型和动态绑定
多态:存在继承关系的几个类,在定义的时候,都用到根类的名字,不过在运行时,会根据具体的类型,调用不同子类的方法。
动态类型:id 可以接受任何的数据类型,缺点就是容易发生运行时异常。
id定义的时候,不用加星号。 id a = b;
运行阶段,才能确定的类型。
动态绑定:程序运行过程中,一些id类型的类,会根据实际情况,进行响应的类分配。
运行阶段,才能确定调用的方法。
9. 如何定义一个objc的字符串?
基本上objc的东西都带ns前缀。
NSString *str = @"hello world!"
10. 处理动态类型的一些方法有哪些?
首先要知道获得类实例(class-object)的方法,例如class a , [a class];
下面是一些方法:
(1) 对象是不是class-object或其子类的成员- ( BOOL) isKindOfClass: class-object
(2) 对象是不是class-object的成员? - (BOOL) isMemberOfClass: class-object
(3) 对象是否包含selector所指定的成员? - (BOOL) respondsToSelector: @selector
(4) 指定的类实例是否包含selector所指定的方法? + (BOOL) instancesRespondToSelector: @selector
(5) 对象是指定类的子类吗? + (BOOL) isSubclassOfClass: class-object
(6) 调用selector指定的方法? - (id) performSelector: @selector
(7) 同6 - (id) performSelector: selector withObject: object
(8) -(id) performSelector: @selector withObject:object withObject:object
isKindOfClass and isMemberOfClass的区别?答:isKindOfClass检测继承层次中的关系,isMemberOfClass检测直接成员的关系。
11. objc 中也存在异常处理机制, try..catch…
格式如下:
@try {
}
@catch(NSException *exception) {
}
12. 如何初始化NSArray?
答:NSArray *arrs = [[NSArray alloc] initWithObjects: @"a", @"b", @"c", nil];
or
NSArray *arrs = [NSArray arrayWithObjects:@"a", @"b", nil];
13. 编写初始化方法的时候,一般都要在首行编写:
self = [super init]; // 即调用父类的初始化方法,不一行是init的写法。
然后判断是否初始化成功了:
if ( self ) {
}
14. objc中也存在作用域修饰关键字,不过只有对实例变量的修饰:
@propected (默认)
可以被任何子类访问
@private
只能被自己访问,不能被子类访问
@public
能被其他类或模块访问,此修饰之后,还能用->的方式访问修饰的变量,根C++中相同。
@package
@package is similar to internal for .NET. It means the member is accessible only from the framework in which it is defined.
Note: In 32-bit it acts like @public.
举例写法:
@interface Person : NSObject {
@private
int handNum;
@propected
int headNum;
}
@end
15. objc中定义全局变量的命名规则。
举例:int gMoveNumber = 0;
前面都要加一个 g 代表是全局变量
16. 定义全局变量2中方法。
(1)在所有类,方法外,直接定义 int gCount;
(2)在方法里面,用关键字extern修饰。
- (void) setABC : (int) val {
// 定义全局变量
// extern int gCount = 0; 这种写法是错误的 extern定义的变量不能直接赋值
extern int gCount;
gCount = 1;
}
17. 在objc中,应该尽量少用extern即外部/全局变量,应该用static来代替extern.
为什么要这样? 因为外面变量可以被其他任何文件访问到,而static 可以编写相应的方法进行访问,在安全性上比全局变量好。
18. auto关键字,这个关键字几乎天天看到,只不过“隐形”了。例如
int count < == > auto int count;
语义就是,进入方法,分配内存,结束方法,释放内存。
19. 常量的定义关键字 const
const int a = 100;
20. volatile关键字的作用。
与const相反,定义变量是可变的。
为什么要用呢?
*outPort = 'O' ;
*outPort = 'N' ;
正常的情况下,编译器发现outPort被重复赋值,就会把第一次outPort从编译器中除去。
如果定义:
volatile char *outPort;之后,就不会在编译环境中除去了。这在特殊环境中有作用。
21. 枚举数据类型 enum 如何定义及作用?
答:
定义:
enum month {
january = 1,
february,
march,
april,
may,
june,
july,
august,
september,
october,
november,
december
};
作用:
归类,把一组有意义的词语封装起来。
22. objc中typedef的作用是什么?
答:顾名思义: typedef = type(类型) + define(定义)
为数据类型,另外指派一个名称。
作用是增加了变量定义的可读性。
例如:
typedef int Counter;
Counter num = 0;
23. 通常typedef 与enum连用。如下:
typedef enum {
january = 1,
february
} MONTH;
// typedef enum { january =1, february } Month;
这样与enum Month {…} 有什么区别呢?
答: 这样 在定义变量的时候就不用enum了
Month thisMonth = february;
enum Month thisMonth = february;
24. 扩展新类方法的方式有哪些?
答:(1)继承 (2)重载 (3)分类 (4)协议
25. 分类扩展的方式举例
#import "Fraction.h"
@interface Fraction (MathOps)
- (void) methodA;
- (void) methodB;
@end
@implementation Fraction (MathOps)
- (void) methodA {
}
/* 分类中的方法可以不实现
- (void) methodB {
}
*/
@end
26. 使用分类时的注意事项。
(1)使用分类时,不能添加实例变量。
(2) 在分类中定义方法时,注意不能与原类方法重名,不然原方法将被覆盖。
(3) 分类中的方法,可以不实现。
27. objc的协议。
(1)格式:
@protocol XXX
- (void) methodX;
@end
(2)本质,定义了一系列没有实现的方法。
(3)协议的使用
@interface Fraction <XXX /* , ??? 多个协议用‘,’隔开*/>
@end
@implementation Fraction
// XXX中的方法不是必须实现的,如果没有实现,xcode会产生警告
- (void) methodX {
NSLog(@"implement the method which in @protocol XXX");
}
@end
28. 父子类协议示意图
父 ----<遵守协议a>
| |
| |
|
子 <-----
29. 问,我用了一个自己写的协议XY, 但是我没有实现协议中的方法,这样编译器就会给我发一则警告,如何让它不警告。
代码如下:(协议应该定义在单独的文件中)
@protocol XY
- (void) xyMethod;
@end
/////////////////////
@interface Fraction <XY>
@end
@implementation Fraction
// 不实现xyMethod方法
@end
==== 若修改代码 ====
@protocol XY
@optional
- (void) xyMethod;
@end
加上@optional关键字 就不会产生警告了。
30. 如何检查一个对象是否遵循某项协议
- (BOOL) conformsToProtocol: 方法
例如:[currentObject conformsToProtocol: @protocol (Drawing)]
31. 什么是合成对象?
一个类包含其他类的一个或多个对象。 这个类实例化出来的对象就叫做合成对象。
例如:
@interface Square : NSObject {
Rectangle *rect;
}
@end
32. 简单说说预处理程序?
& 几点理解:
(1)定义‘特殊常量’
(2)定义表达式和任何东西
(3)类似于程序中的全局文本替换
& 定义预定义名称的时候,一种写法是全都用大写,另一个是名称前面加k,例如:
#define TURE 1 #define kTure 1
&#define 语句的基本用途之一就是给符号名称指派程序常量,例如:
#define TURE 1
& 定义表达式,例如:
#define TWO_PI 2.0 * 3.141592653
& 为什么预定义后面不能写';'?
答:因为预定义的本质是文本替换,如果最后加上了分号,分号也将被替换到程序中。例如:
#define PI 3.1415926 ;
return PI * r; == > return 3.1415926; * r;
& 看如下预定义是否正确,若错误,错在哪里?
#define IS_LEAP_YEAR year % 4 == 0 && year % 100 != 0
|| year % 400 == 0
答:错误,预定时语句,如果过长,写在两行时,第一行的结尾处要添加 ‘\’告知编译器还有后续
内容。 修改如下:
#define IS_LEAP_YEAR year % 4 == 0 && year % 100 != 0 \
|| year % 400 == 0
& 预定义语句可以带参数,如下:
#define IS_LEAP_YEAR(y) y % 4 == 0 && y % 100 !=0 \
|| y % 400 == 0
*** 注意,这种写法有陷阱存在,正在下面有提到. 正确的写法是 #define IS_LEAP_YEAR(y) (y)%4 ==0 && (y)%100 != 0 || (y) %400 ==0
使用预定义的时候,写法如下:
int year = 2012;
if (IS_LEAP_YEAR(year)) {
NSLog(@"2012 year is leap year! ");
}
这里有一点需要注意:带有参数的预定义,预定义名称与参数列表的左半边括号不能有空格。例如:
#define IS_LEAP_YEAR (y) .. 就是错误的写法。为什么呢??
答:因为预定义时文本替换,如果有空格,就会把 IS_LEAP_YEAR替换成 “(y) y % 4 == 0 && y %
100 !=0 \ || y % 400 == 0 ”
& 预定义也叫宏定义,宏定义存在一个‘陷阱’, 如下:
#define kSquare(x) x * x
int v = 100;
return kSquare(v + 1);
这里,通常人们会认为kSquare(v + 1) 得到的结果时 (v + 1) * (v + 1),可时宏定义时文本替换,所以
看替换的结果,
x * x == > v + 1 * v + 1 ;
解决办法:
#define kSquare(x) ( (x) * (x))
这样替换的结果为 ((v + 1) * (v + 1))
& 定义一个宏,判断某字母是否是小写字母?
答:
#define IS_LOWER_CASE(x) ( ( (x) > 'a' ) && ( (x) < 'z') )
& 定义一个预定义,把小写字母转换成大写字母?
答:
#define TO_UPPER(x) ( IS_LOWER_CASE(x) ? ((x) - 'a' + 'A') : (x) )
& 宏定义中的 #
若果在定义宏的时候,在参数前放置# ,则结果不是替换,是把宏参数转成c风格的字符串。如下:
#define str(s) #s
str(testing);的结果为: "testing"
另一个例子:
#define printInt(var) printf(#var " = %i\n", var)
int count = 100;
printInt(count) == > printf("count" "= %i\n", count);
& 宏定义中的 ##
答:##在宏定义中是连接符作用。如下:
#define printf(n) printf(x ## n )
int n = 100;
printf(n) == > printf(x100)
33. 简单说说条件编译?
& objc中预处理程序提供了一项名为条件编译(conditional compilation)的功能。
& 条件编译的用途是什么?
条件编译通常用于创建可以在不同计算机系统上编译运行的程序。它还经常用来开关程序中的各种语
句,例如:用来输出变量值或跟踪程序执行流程的调试语句。
& 条件编译的关键子有哪些?
答:#ifdef , #endif, #else , #elif , #ifndef. 举例如下:
#ifdef MAC_OS_X
# define DATADIR "/uxn1/data"
#else
# define DATADIR "\usr\data"
#endif
& 在程序中,如何应用呢?
答:[预留]
34. 什么是框架, 及其作用?举几个常用的框架。
答:框架是由许多类,方法,函数,文档按照一定的逻辑组织起来的集合。以便使研发程序变得更容易。
— Foundation框架是基础框架,主要是允许用一些基础对象,如数字和字符串。还允许使用对象集合 如,数组,字典和集合,还由一些日期处理,自动化内存管理,文件系统等
— Application Kit 框架:用来开发交互式图形应用程序。
Cocoa = Foundation + Application Kit
Cocoa Touch = Foundation + UIKit
35. Foundation框架提供的基础对象是什么?
答:数字,字符串, 集合。
集合包括:数组, 字典, 集。
36. NSNumber 是对象,还是typedef? 它可以封装哪些基础类型?
答:NSNumber 是对象,他可以封装int float double BOOL char long. 他们的初始化方法都是对应的。
[NSNumber numberWith…];
例如:int类型就是NSNumber *myInt = [NSNumber numberWithInteger: 100];
37. Xcode 4.3.3 以后的release为何不可用了??
答:Xcode4 ARC(Automatic Reference Counting)有所变动,Xcode4.3自动在compile time处理release,也就是,你写alloc,compiler自动在code gen时加入相对的release,这作法是为了解决iOS仰赖程式设计师(app designer)负责memory management的问题(也就是你alloc後必需自己release这问题)。
不想用ARC的话,在Xcode4.3 File/New/New project及Choose a template for your new project选定template後的Choose options for your new project画面,"不勾选"UseAutomatic Reference Counting,这样你就可在你的project中试用alloc/release了。
38. #define 与 typedef 如何区分?
答:& define 定义,文本替代。
#define PI 3.14
& typedef 类型定义,顾名思义,就重新定义类型的。
typedef struct _NSRange {
NSUInteger location;
NSUInteger length;
} NSRange;
39. NSLog(@"%2i") 与 NSLog(@"%i") 的区别是什么?
答:2i,不足2位的值不是补零,就是补空格
40. NSArray不能存放简单类型,只能存放对象。
41. C语言本身提供数组与Foundation提供的数组,你用哪个?为什么?
答: C语言本身提供的数组是最底层的数组,虽然操作复杂,但是效率高.
Foundation提供的数组,操作相对容易,但是效率相对比C语言本身低。
42. 数组的一种快速循环的方法是什么?
NSArray *arr = [NSArray arrayWithObjects:@"sdf",@"dfdsa", nil];
for (NSString* temp in arr) {
NSLog(@"%@", temp);
}
43. 数组的排序问题,也是面试、工作长问的问题?
答:
44. 分别说出NSArray 和 NSMutableArray的5个常用方法。
答:& NSArray : [NSArray arrayWithObjects: obj1, obj2, obj3…, nil]
[array1 containsObject: obj]
[array1 objectAtIndex: i]
[array1 count]
[array1 indexOfObject: obj];
& NSMutableArray: addObject:obj
insertObject:index
arrayWithCapacity: size
replaceObjectAtIndex: i withObject:obj
removeObject: obj
removeObjectAtIndex: i
45. 词典对象,和键关联的值可以是任何对象,但他们不能为nil.
46. 用for( in ) 遍历字典的时候,例如:
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:
@"HELLO WORLD",@"name" ,
nil];
for (NSString *key in dic) {
NSLog(@"%@",[dic objectForKey:key]);
}
从字典遍历出来的是key值,然后通过key值,取出value.
48. NSSet 和NSMutableSet里面如果存放了相同的对象,则会自动删除重复的。 如果要保持重复的,那么用NSCountedSet。
49. 两个集合如何求交集和并集?
答:& 举例如下:
NSMutableSet *set1 = [NSMutableSet setWithObjects:@"1", @"2", @"3", nil];
NSMutableSet *set2 = [NSMutableSet setWithObjects:@"1", @"4", @"5", nil];
[set1 unionSet: set2];
NSLog(@"%@", set1);
& 交集: 可以通过 BOOL flag = [ set1 intersectsSet: set2] ; 判断是否存在交集. 如果有. 循环俩个Set 进行比较.
50. NSCountedSet的本质?
答:NSCountedSet 并不是存储相同对象的两份,而是由几个计数器,专门计算每个对象存储的数量。
countForObject专门计算每个对象的数量。
51. xcode 4.3.3以后的内存管理发生了什么改变?例如:[obj retainCount]; [obj retain]; [obj release];都不可
用了。
答: 同标签 37.
52. 正是协议与非正式协议的区别?
答:正是协议的方法必须全部实现,非正是协议的方法不必全部实现。
53. 在@interface中,不能直接赋值,如下是错误的:
@interface a : NSObject {
// int a = 100;
int a; // 正确的写法
}
@end
--------------------------- 2012 年 8 月 13 日更新 -------------------------------------------
54. 全局变量 和 extern的使用举例 ?
答: 先看例子:
苍井空.h 文件:
#import <Foundation/Foundation.h>
int gCount;
@interface 苍井空 : NSObject
@end
孙悟空.m文件中的方法:
@implement 孙悟空
- (void) use苍井空 {
// 这里要使用 苍井空.h中的 gCount
1.要告诉编译器,我要用一个全局变量.
extern int gCount;
2.就可以正常的应用全局变量了
gCount = 1;
}
@end