@符号表示将使用oc的特殊用法,比如@property @selector
1、大循环时候内存释放问题:
oc中,当较大循环,如1M次时。循环过程中内存占用会绝对增长,即使有自动释放也不会起作用,因为在自动释放不会在循环进行中执行,一定会在循环结束后才执行
如:
int i;
for(i=0;i<1000000;i++){
id object = [somearray objectAtIndex:i];
NSString *desc = [object description];
//otherthings to do
}
在这一百万次循环中,内存一直增加,直到循环结束,自动释放池被销毁时,才会自动释放对象;解决方法:
NSAutoreleasePool *pool;
pool= [NSAutoreleasePool alloc]init];
int i;
for(i=0;i<1000000;i++){
id object = [somearray objectAtIndex:i];
NSString *desc = [object description];
//otherthings to do
if(i%1000==0){//循环1000次进行一次销毁,并创建新的pool
[pool release];
pool =[[NSAutoreleasePool alloc]init];
}
}
[pool release];
//ps:自动释放池分配和销毁的操作代价很小,以至于可以每次循环都进行创建销毁操作;
2、启用ARC之后,通常的内存管理命令都成了空指令;iPhone开发不建议使用arc
3、oc中,初始化对象包括两步:分配(allocatin)和初始化(initialization),有别于java和c#
初始化两种常用方法:[类名 new]和[[类名 alloc] init] ,cocoa中通常使用后者(不会使用后者的程序员才会使用前者,所以你懂的)
4、分配:执行从os中获取内存,指定用于存放对象的实例变量位置,并将内存区域全部初始化为0
初始化:从os中取得内存,准备用于存储对象;
类方法alloc对对象分配内存区域并清零该区域,实例方法init用于获得一个对象并使其运行;
5、使用if(self=[super init])的原因是初始化可能返回完全不一样的对象,
建议使用 if(self = [super init])类似这种方法
6、注意“惰性求值”
7、不是通过alloc、copy、new方法创建的对象它的保留计数器的值为1,而且可以认为是自动释放的,所以不用手动释放
8、使用set时候,最好使用“保留以前已传入的对象并释放当前对象”,例如:
-(void) setEngine:(Engine *) newEngine{
[newEngine retain];//已传入的保留
[engine release];//此处的engine是当前对象,释放掉
engine = newEngine;//完成赋值
}//setEngine
9、指定初始化函数:该类的所有初始化方法使用指定初始化函数进行初始化操作,子类使用其超类的指定初始化函数进行超类的初始化,通常使用接受参数最多的初始化方法成为指定初始化函数,其他则使用类似指定初始化函数的形式。(在初始化函数不止一个的时候需要指定初始化函数)
10、特性property:@property 表示声明了一个新对象的属性,自动声明该属性的seter和getter
11、@synthesize 表示创建该属性的访问器,当遇到@synthesize someProper; 的时候,编译器会输出-setSomeProper和-someProper方法已编译代码(即setter和getter方法)
12、点表达式:oc2.0之后可以使用类似c++和java的点,如
[tire setRainHandling:20+i];
可以写作:tire.rainHandling=20+i;
点表达式出现在等号左边,自动调用setter方法,在右边自动调用Getter方法,即点表达式是调用访问器的一种快捷方式
13、需要执行copy操作对某属性赋值,则在@property的时候需要声明copy属性,同理,若某对象需要保留,则声明(retain),(nonatomic则是不在多线程使用,可以提升速度,尤其是iphone中),如果不希望保留属性对象,可以使用assign方法避免保留周期问题,声明readonly则只生成getter方法,
14、self在oc中的应用:self.name用来消除歧义,表示期望使用访问器访问name
15,category类别:@interface NSString(someFun)
@end//.h文件
@implenmentation NSString (someFun)
@end//.m文件
16、使用类别可以将单个较大的类以某种条件分为多个小类
eg:
@interface CategorySamp : NSObject {
int samp1;
int samp2;
int samp3;
}
@end //
@interface Category(Samp1){
-(void) setSamp1:(int) samp1;
-(int) samp1;
}
@end//
@interface Category(Samp2){
-(void) setSamp2:(int) samp2;
-(int) samp2;
}
@end//
@interface Category(Samp3){
-(void) setSamp1:(int) samp3;
-(int) samp3;
}
@end//
#import "CategorySamp.h"
@implementation CategorySamp
-(NSString *)describtion{
NSString *desc;
desc=[NSString stringWithFormat:@"%d %d %d",samp1,samp2 ,samp3];
return(desc);
}
@end
还需要在对应的.m文件中添加响应的处理,此处省略
17、非正式协议和委托类别:委托:是一种对象,另一个类的对象要求委托对象执行他的某些操作
18、正式协议:一个命名的方法列表 ,需要显式的在类的@interface中列出协议的名称,这样才表名该类遵守该协议,且需要实现该协议的所有方法,sample code:
@protocol SampleProtocol
@required//后接必须要实现的
@optional//后接可选的,不一定要实现,
//...
@end
引用时 @interface SampClass:NSObject<SampleProrocol>...
19.复制 copy :浅层复制(Shallow Copy)不复制引用对象,新复制的对象只指向现有的引用对象;深层复制(deep copy)将复制所有的引用对象
20、plist 属性列表包括:NSArray,NSDictionary,NSString,NSNumber,NSDate,NSData及它们的变体(ifexists)
21、通过KVC,可以获取不存在getter和setter方法的对象值,无需通过对象指针直接访问实例变量,即通过setValue和valueForKey,
22、NSPredicate 指定过滤条件,类似sql中的where,使用此类可以省去很多不必要的循环等操作,sampleCode :NSArray *array =[ [ NSArray alloc] initWithObjects: @"f1",@"f2",@"f3",@"s1",nil];
NSString *str = @"f";
NSPredicate *predicate = [NSPredicateWithFormat:@"SELF CONTAINS %@",str];
NSLog("after predicate:%@",[array, filteredArrayUsingPredicate:predicate];
除了过滤Array,还能对字符串首字母判断,字符替换,截取字符串,判断手机号码,邮箱验证NSDate筛选等诸多操作,详见http://blog.csdn.net/ztp800201/article/details/8116081;
(SELF CONTAINS 是字符串比较操作符,不是集合操作符)
23、通常的引用有两种方法: 1. 通过#import 2.通过@class
前者方式会包含被引用类的所有信息,包括被引用类的变量和方法,后者只是告诉编译器在A.h中 B *b只是类的声明,如果需要引用这个类的实体变量或者方法,还是需要import;@class可以处理互相引用而导致死循环问题, 多层@import极度耗费时间,大型软件中需要减少.h文件的include。
当A.h中仅需要声明一个B的指针时候,在A.h中声明 @B
B *b;
使用原则: 头文件只import超类,消息文件里面import需要发消息过去的类,其他地方就用@class转向声明
24、真机调试时,Entitlements.plist中添加的get-task-allow如果没勾选,也有可能导致提示证书无效无法真机调试,这个原因待查证。
--------------------------------------------分割线-----内存管理专题-------------------------------
25、自动释放池中如果有大量的autorelease,则需要注意控制数量,因为在如果自动释放池没有销毁,这部分都将保留,等到pool销毁的时候再销毁,很容易导致内存不足,如sample Code:
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{
for (j = 0; j < 100000; j++ )
[NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。
}
[pool release];
return (0);
} // main
26、除了alloc、new或copy之外的方法创建的对象都被声明了autorelease,release一个空指针是合法的,但是不会发生任何事
27、OC的对象生成于堆之上,生成后需要一个指针来指向:ClassA *obj1=[[ClassA alloc]init];
OC中的ref count或者retain count表示对象被引用的次数:即,如果被两个指针指向,则count为2
需要销毁的时候调用release,则减1,为0时才会调用dealloc真正销毁该对象
ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1//注意为何此处的count为1,因为该指针指向的obj1,而
//不是指向生成的对象
[obj1 hello]; //输出hello
[obj1 release]; //retain count = 0,对象被销毁
[obj2 hello];
[obj2 release];
[obj1 release]之后,obj2依然是个无效指针,处理类似问题的方式如下:ClassA *obj2 = obj1; 后面加上 [obj2 retain];//使count+1,(虽然能解决此问题,但是略麻烦,更简单的方法见下:)
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj2 retain]; //retain count = 2
[obj1 hello]; //输出hello
//对于obj1,无需调用(实际上不能调用)release
[obj2 hello]; //输出hello
[obj2 release]; //retain count = 2-1 = 1//问题:为何此时的count依然为1,如何销毁?因为对象是使用autorelease标记过的,被记录入释放池中,会被记录池清理
自动释放池中大规模循环释放的示例:
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
for (j = 0; j < 100000; j++ )
[NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。
[loopPool release];
}
[pool release];
return (0);
} // main
28、谁retain,谁release,谁创建,谁释放:只要你调用了retain,无论这个对象是如何生成的,你都要调用release
29、释放模版:1.release一个对象后,立即把指针清空:[obj1 release]; obj1=nil;
2.指针赋值给另一个指针:
ClassA *obj2=obj1;
[obj2 retain];
//todo something
[obj2 release];
obj2=nil;
3.在一个函数中创建并返回对象,需要把这个对象设置为autorelease
ClassA *Func1(){
ClassA *obj=[[[ClassA alloc]init]autorelease];
return obj;
}
4.在子类的dealloc方法中调用基类的dealloc方法
-(void)dealloc{
...
[super dealloc];
}
5.
0 0