属性项目的定义(property)与内存管理问题

来源:互联网 发布:sql数据库查询软件 编辑:程序博客网 时间:2024/05/17 01:44

 

一些iPhone的系统目录

得到Document目录:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);NSString *documentsDirectory = [paths objectAtIndex:0];

得到temp临时目录:

NSString *tempPath = NSTemporaryDirectory();

得到目录上的文件地址:

NSString *文件地址 = [目录地址 stringByAppendingPathComponent:@"文件名.扩展名"];

iphone程序的开始画面设置

iPhone软件启动后的第一屏图片是非常重要的往往就是loading载入中的意思。设置它说来也简单,但是却无比重要

只需要在resource里面将你希望设置的图片更名为Default.png,这个图片就可以成为iPhone载入的缺省图片

屏幕快照 2009-07-25 上午10.50.19

 

64位编程:整数/小数

对应64位编程的时候,

对于整数应使用NSInteger和NSUInteger,而非int

对于小数应使用CGFloat,而非float

NSInteger其实是一个自动定义,在32位中为int,而64位中为long。CGFloat的原理类似

 

delegate参数解析

D 在Cocoa里面很多对象的初始化都有一个delegate参数,例如初始化一个ActionSheet

[[UIActionSheet alloc]   initWithTitle:@"标题"   delegate:self   cancelButtonTitle:@"取消按钮"   destructiveButtonTitle:@"结束按钮"   otherButtonTitles:nil];

这里就有一个delegate参数,而我给的例子里面的值是self。

那这个self是什么含义呢?

还有什么其他可行参数么?

答案如下:

1,正如delegate的中文含义是“事件代理”,这里就是要为ActionSheet找一个代理。那么如果写self,那就意味着本地对象和本地类就是这个ActionSheet的“事件代理”。那么我们就应该在这个本地类里面写delegate的方法来回应。例如:

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex{}

2,本地类如果不是对象类的时候,是没有该对象(ActionSheet)的事件代理解析能力的,这时该怎么办呢?那么就应该在本地类加入对象类的“事件代理”协议(接口),如下:

@interface aViewController : UIViewController <UIActionSheetDelegate>{}

这里的<UIActionSheetDelegate>就告诉本地类去接收并可以响应ActionSheet的“事件”

3,如果有多个ActionSheet在一个本地类中,这个事件代理该如果响应呢?

方法如下:

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex{if(actionSheet == 指定的actionSheet对象){}}

事件代理方法的第一个参数就是发出事件代理的对象,所以可以进行比对后,作if参数调节。

4,delegate后可使用nil值。这个就表示该对象不被代理。

5,delegate后可以使用本地类可以访问的类对象,这样那个类对象就会收到ActionSheet的代理通知。例如:ClassB是ClassA的子类,ClassA中有一个需要代理的ActionSheet, ClassA可以通过这个delegate参数来指定ClassB作为这个ActionSheet的事件代理。

此贴暂时就到这里,以后会进行完善,并添加“屏播”解释。

 

 

在子类(sub-class)中覆盖“初始化”和“默认”函数

I 在CS193P中,Evan强调了以下问题:

为什么要在覆盖init的时候需要检查是否在父类中作初始化,例如:

- (id)init{if(self = [super init]){}}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {        // Custom initialization    }    return self;}

主要是将本地对象用父类的init进行初始化,其中的等号“=”另一方面检查了是不是成功进行了初始化。CS193P提供了更多关于这个的信息:

http://cocoadev.com/index.pl?FactoryMethod

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

不仅仅是init等初始化对象,还有其他一些方法(Method)是需要对自己的父类打声招呼得,例如:

- (void)viewDidLoad {    [super viewDidLoad]}

那这个没有super这句会怎么样呢?没事,一样用。这个是一个delegate,所以需要收听的类应该会收听到的。但是既然缺省的方法就是这么写的,我们也没有必要特意去删除掉这个super方法。 

 

对比:id与NSObject

N 以下是来自CS193P的笔记:

1,id关键字在编译时不被检查,而NSObject在编译时会被检查是否被调用一些错误方法。

2,id可以是任何对象,包括非NSObject对象

3,定义id的时候不使用*,NSObject却需要。

我的理解,基本上来讲,定义id类似于定义了一个地址(只有指针,抽象指针),而NSObject是确实的定义了一个逻辑对象的地址。

一个来自CS193P笔记的链接:

http://unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html

 

 

属性项目的定义(property)

 @property (copy, nonatomic) NSString *title;

什么是assign,copy,retain之间的区别?

  • assign: 简单赋值,不更改索引计数(Reference Counting),因为基本上是为简单数据类型准备的,而不是NS对象们。
  • copy: 建立一个索引计数为1的对象,然后释放旧对象
  • retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1

Copy其实是建立了一个相同的对象,而retain不是:

比如一个NSString对象,地址为0×1111,内容为@”STR”

Copy到另外一个NSString之后,地址为0×2222,内容相同,新的对象retain为1,旧有对象没有变化

retain到另外一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1

也就是说,retain是指针拷贝,copy是内容拷贝。哇,比想象的简单多了

 

retain的实际语法为:

- (void)setName:(NSString *)newName {    if (name != newName) {       [name release];       name = [newName retain];       // name’s retain count has been bumped up by 1    }}

说了那么麻烦,其实接下来的话最重要:

?如果你不懂怎么使用他们,那么就这样 ->

  • 使用assign: 对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等)
  • 使用copy: 对NSString
  • 使用retain: 对其他NSObject和其子类

nonatomic关键字:

atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。

 

 

Objective-C内存管理

1,你初始化(alloc/init)的对象,你需要释放(release)它。例如:

NSMutableArray aArray = [[NSArray alloc] init];

后,需要

[aArray release];

2,你retain或copy的,你需要释放它。例如:

[aArray retain]

后,需要

[aArray release];

3,被传递(assign)的对象,你需要斟酌的retain和release。例如:

obj2 = [[obj1 someMethod] autorelease];

对象2接收对象1的一个自动释放的值,或传递一个基本数据类型(NSInteger,NSString)时: 你或希望将对象2进行retain,以防止它在被使用之前就被自动释放掉。但是在retain后,一定要在适当的时候进行释放。

 

为什么不能直接调用dealloc而是release

M 在看过CS193P的笔记后,以下是真正有用的句子:

dealloc不等于C中的free,dealloc并不将内存释放,也不会将索引计数(Reference counting)降低。于是直接调用dealloc反而无法释放内存。

在Objective-C中,索引计数是起决定性作用的。

数据类型/对象类型介绍(1)NSString

字符串是程序设计最常用的数据类型之一了。在Mac/iPhone编程中,苹果为我们提供了一个不同的字符串类型NSString。有别与普通的String为数据类型,NSString其实是一个对象类型。NSString是NSObject(Cocoa Foundation的基础对象)的子类,所以具有NSObject的所有特性,好的和好的… ….

小常识:NS是Cocoa类对象类型的前缀,来源于史蒂夫-乔布斯被苹果开除那段时间建立的公司NeXT.@是Cocoa元素的前缀,很多地方我们会看到,比如接下来...

1, 创建一个NSString对象

简单方法:

NSString *aString = @"我是个NS字符串!";  //除了引号外加@, 没别的区别

*上面的不需要操心内存管理哟~

复杂一点儿:(需要内存管理的)

NSString *aString = [[NSString alloc] initWithFormat:@"这也是个NS字符串!"];

*initWithFormat是其中一个初始化方法,常用的还有

//从一个文件读取需要的内容- (id)initWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error//从一个地址读取需要的内容- (id)initWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error

*以上方法得到的NSString的retain值为1,所以记得release掉阿~~

2,使用一个NSString对象

NSString *aString = @"This is a NSString"; NSLog(aString);   //在控制台输出信息,该函数方法需要一个NSString对象作为参数 NSLog("这样不会好使的"); NSLog(@"这样就会好使拉~");

再比如设置一个UIView的标题:

[UIView setTitle:aString][UIView setTitle:@"标题"]; UIView.title = aString;

3,释放NSString

[aString release]; //对象将被系统释放掉咯

*记得不要释放直接用 = @”xxx” 的NSString对象哟,系统会管的~

4,快速使用一个NSString

NSLog([NSString stringWithFormat:@"一个NS字符串"]);

//这种快速方法返回的是一个retain为1,autorelease的对象,不需要操心它的内存管理

5,常用方法

我喜欢NSString的地方就在于很多方法非常方便,比如:

nString = [aString substringToIndex:4]; //nString将得到aString中的前四个字符

6,小结

暂时能记起来的就这么些了,有机会再补充,希望大家NS的愉快~

 

 

 

NSString的内存管理

 

CS193P的笔记上有如下实例:

aString = @"I am a string that 2 years old, man!";

这种情况下,字符串储存和管理由系统做,我们不用操心。

aString = [NSString stringWithFormat:@"I am a string that %d years old, man!",2];

第二种情况下,我们需要去retain和release这个字符串,系统不管。

 

 

多线程之NSInvocationOperation

原文:http://c.gzl.name/archives/category/cocoa/cobjc

 

T 多线程编程是防止主线程堵塞,增加运行效率等等的最佳方法。而原始的多线程方法存在很多的毛病,包括线程锁死等。在Cocoa中,Apple提供了NSOperation这个类,提供了一个优秀的多线程编程方法。

本次介绍NSOperation的子集,简易方法的NSInvocationOperation:

@implementation MyCustomClass - (void)launchTaskWithData:(id)data{    //创建一个NSInvocationOperation对象,并初始化到方法    //在这里,selector参数后的值是你想在另外一个线程中运行的方法(函数,Method)    //在这里,object后的值是想传递给前面方法的数据    NSInvocationOperation* theOp = [[NSInvocationOperation alloc] initWithTarget:self                    selector:@selector(myTaskMethod:) object:data]// 下面将我们建立的操作“Operation”加入到本地程序的共享队列中(加入后方法就会立刻被执行)    // 更多的时候是由我们自己建立“操作”队列    [[MyAppDelegate sharedOperationQueue] addOperation:theOp];} // 这个是真正运行在另外一个线程的“方法”- (void)myTaskMethod:(id)data{    // Perform the task.} @end

一个NSOperationQueue 操作队列,就相当于一个线程管理器,而非一个线程。因为你可以设置这个线程管理器内可以并行运行的的线程数量等等。下面是建立并初始化一个操作队列:

@interface MyViewController : UIViewController {     NSOperationQueue *operationQueue;    //在头文件中声明该队列}@end @implementation MyViewController - (id)init{    self = [super init];    if (self) {        operationQueue = [[NSOperationQueue alloc] init]; //初始化操作队列        [operationQueue setMaxConcurrentOperationCount:1];        //在这里限定了该队列只同时运行一个线程        //这个队列已经可以使用了    }    return self;} - (void)dealloc{    [operationQueue release];    //正如Alan经常说的,我们是程序的好公民,需要释放内存!    [super dealloc];} @end

简单介绍之后,其实可以发现这种方法是非常简单的。很多的时候我们使用多线程仅仅是为了防止主线程堵塞,而NSInvocationOperation就是最简单的多线程编程,在iPhone编程中是经常被用到的。

 

 

多线程 之 NSOperation

多线程编程是防止主线程堵塞,增加运行效率等等的最佳方法。而原始的多线程方法存在很多的毛病,包括线程锁死等。在Cocoa中,Apple提供了NSOperation这个类,提供了一个优秀的多线程编程方法。

本次讲解NSOperation的使用方法:

1,将想在另外一个线程的工作单独成类,并设置其父类为NSOperation:

@interface ImageLoadingOperation : NSOperation {    NSURL *imageURL; //这个例子里面需要传入一个图片地址,所以定义一个NSURL变量    id target; //由于需要返回一些值,所以需要一个对象参数返回要被返回的对象(运行此线程的类对象)    SEL action; //返回值要激发的方法函数}

2,借由其初始化方法来传入所需要的参数和对象

- (id)initWithImageURL:(NSURL *)theImageURL target:(id)theTarget action:(SEL)theAction{    self = [super init]; //在老帖里面解释过为什么需要这么做了    if (self) {        imageURL = [theImageURL retain]; // 拷贝进对象,并retain(为什么?请查老帖)        target = theTarget;        action = theAction;    }    return self;}

呼叫这个类对象的时候,传入所需要的参数和对象

// 这些是需要对其初始化的类中的代码ImageLoadingOperation *operation = [[ImageLoadingOperation alloc] initWithImageURL:url target:self action:@selector(didFinishLoadingImageWithResult:)];  //初始化[operationQueue addOperation:operation]; //添加到运行队列[operation release];  //由于队列对其retain,所以我们需要release它

3,在我们的线程操作类中的main函数执行所需要的工作

- (void)main{    // 同时载入图片    NSData *data = [[NSData alloc] initWithContentsOfURL:imageURL];    UIImage *image = [[UIImage alloc] initWithData:data]// 打包返回给初始类对象,然后执行其指定的操作    NSDictionary *result = [NSDictionary dictionaryWithObjectsAndKeys:image, ImageResultKey, imageURL, URLResultKey, nil];    [target performSelectorOnMainThread:action withObject:result waitUntilDone:NO][data release]; //不需要了就清理    [image release];}

这些就是一个简单的NSOperation的使用过程了。其实看看嘛,非常简单的,正如苹果为我们准备的其他API一样!

 

 

 

 

 

关于索引计数(Reference Counting)的问题

 

M *retain值 = 索引计数(Reference Counting)

  • NSArray对象会retain(retain值加一)任何数组中的对象。当NSArray被卸载(dealloc)的时候,所有数组中的对象会被执行一次释放(retain值减一)。不仅仅是NSArray,任何收集类(Collection Classes)都执行类似操作。例如NSDictionary,甚至UINavigationController。
  • Alloc/init建立的对象,索引计数为1。无需将其再次retain。
  • [NSArray array]和[NSDate date]等“方法”建立一个索引计数为1的对象,但是也是一个自动释放对象。所以是本地临时对象,那么无所谓了。如果是打算在全Class中使用的变量(iVar),则必须retain它。
  • 缺省的类方法返回值都被执行了“自动释放”方法。(*如上中的NSArray)
  • 在类中的卸载方法“dealloc”中,release所有未被平衡的NS对象。(*所有未被autorelease,而retain值为1的)

 

对autorelease的误解

A Cocoa的内存管理分为 索引计数法(Reference Counting/ Retain Count)和 垃圾收集法(Garbage Collection)。而iPhone上目前只支持前者,所以autorelease就成为很多人的“捷径”。

但是!autorelease其实并不是“自动释放”,不像垃圾收集法,对对象之间的关系侦测后发现垃圾-删除。但是autorelease其实是“延后释放”,在一个运行周期后被标记为autorelease会被释放掉。

切记小心使用autorelease,理解autorelease,防止在你还需要该对象的时候已经被系统释放掉了。

 

Cocoa不同内存管理环境下的autorelease

 混合内存管理环境:垃圾收集法(Garbage Collection)+索引计数法(Reference Counting)

虽然大多数情况下混合环境是不被推荐的,但是如果在这个情况下,autorelease需要注意以下事项:

垃圾收集混合环境下:应该使用drain方法,因为release在GC模式下没有意义

索引计数环境下:drain和release对于autoreleasepool(自动释放池)的效果相同

Interface Builder参与的内存管理问题

I 要点:

  • 如果一个变量在类中被定义为了 IBOutlet 那么你无需对其进行实例化,xib载入器会对其初始化。
  • 如果一个变量在类中被定义为了 IBOutlet 那么你必须负责将其释放。xib载入器不会帮忙的… …

*切不要初始化两回,内存会溢出,而且对象锁定也会出错。

 

不要对viewController作这样的事情

错误:

UIViewController *aViewController = [[UIViewController alloc] init][window addSubview:aViewController.view][aViewController release];

这样的话,系统会崩溃的… window或着其他父视图是不会retain整个viewController的,这个时候不能立刻release

正确:

[aViewController.view removeFromSuperview][aViewController release];

也就是说,在release之前需要从superview中移除这个viewController的view。如果一直都需要这个view,那就在dealloc里面作这些事情就可以了

 

 

误释放对象

问题一:

value = [array objectAtIndex:n]; //得到一个数组中的对象[arry removeObjectAtIndex:n]; //卸载那个对象

因为value得到了那个对象,但是由于另外一个拥有者release了该对象,所以其实value现在成了摇摆指针(无效数据)

问题二:

myArray = [NSArray array];...[myArray release];

NSArray返回的是一个自动释放对象,不仅myArray不应该在一段时间后release,而应该在适当的时候先retain,以防止该array被系统误释放。

问题三:

rocket = [rocketLauncher aRocket];[rocketLauncher release];

和array这种数据收集类对象一样,如果我们得到了一个类的子对象而不retain它,那么在原父类被释放的时候,这个rocket其实也会失去其意义。

 

 

 

 

 

最棒的图解MVC

  • 控制器是螺丝,控制两头
  • 数据控件是硬盘,储存数据
  • 视图控件是界面,就是界面… …
  • 控制器接收视图的特定行为(target-action)和 代理通告(delegate)
  • 控制器视图接收数据的通知 和 KVO(键值观察)

 

常用编程快捷键(Xcode/Emacs)

control-F: 向右一个字符(forward)

control-B: 向左一个字符(backward)

control-P: 前一行(previous)

control-N: 后一行(next)

control-A: 去行首

control-E: 到行尾(end)

control-T: 调换光标两边的字符(transpose)

control-D: 删除光标右侧字符(delete)

control-K: 删除本行剩余的字符(kill)

control-L: 居中插入点到屏幕中央(lock)

 

在iPhone上显示LCD效果

我看到一个程序是这样样子的:

屏幕快照 2009-08-13 下午12.36.21

哇!好厉害,怎么弄出来的!难道要用Q2D画出来么?

不… …

其实这就是UILabel外加一个奇异的字体 DBLCDTempBlack

And, that’s it! 生活多么美好阿

 

 

随机数生成器

R 来做一个小小随机数生成器吧!从1-100~

***Safari浏览的时候似乎会很乱… 换Firefox看这个帖子吧

随机数生成器
随机数生成器
随机数生成器
////  rndNo.m//  RandomNumber////  Created by Zhengliang Guo on 09-6-17.//  Copyright 2009 gzl.name All rights reserved.//

这个程序非常简单,首先建立一个类,选一个自己喜欢的名字:

图片 5

图片 5

看看头文件里面有什么呢?

@interface rndNo : NSObject {IBOutlet NSTextField *textField;}-(IBAction)resetSeed:(id)sender;-(IBAction)genderateNo:(id)sender;@end

m文件里面的洞天:

-(IBAction)resetSeed:(id)sender{srandom(time(NULL));[textField setStringValue:@"随机数种子已重置"];}-(IBAction)genderateNo:(id)sender{[textField setIntValue:(random()%100 +1)];}

在IB里面建立一个对象,然后指定他的类为我的rndNo.

图片 9

//记得将IBAction和IBOutlet连接正确噢~否则不会好使的。//不会在Xcode里面连接对象?在我的博客里面搜索一下吧!

让我们的程序在点击关闭红点的时候也关闭吧:

首先添加所需的事件代理到m文件:

- (void)windowWillClose:(NSNotification *)notification //当窗口关闭的时候{exit(1);  //我们退出程序}

右键点击我们的窗口,然后将delegate连接到我们建立的对象上
图片 5

//编译运行!大功告成,还不赶快自己也试试!

 

 

 

 

 

原创粉丝点击