Categories

Posts Tagged ‘Objective-C’

iPhone开发之Objective-C学习(5)

Objective-C中的属性
在C++中,类可以有自己的成员变量, 一般公有成员变量可以直接通过类对象访问或修改, 保护成员变量和私有成员变量通过相应的函数来存取,比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class CPerson
{
public:
	int	 gender;
protected:
	int age;
public:
	int GetAge(){return age;}
	void SetAge( int newValue){ age = newAge;}
};
 
void test(){
	CPerson person;
	person.gender = 0;
	person.SetAge(20);
	printf("性别:%d",person.GetAge() );
	printf("年龄:%d",person.gender);
 
}

这里申明一个人的类CPerson, 其中表示性别的变量 gender是公有成员变量,可以通过类对象peron直接读写,而年龄age则需要通过Set和Get函数来读写。 同样的在Objectivie-C中也有类似的机制, 不过在Object-C中默认的变量都是私有的, 而且所有变量都只能通过存取函数或者访问器来访问,而且在Objective-C中把可以通过访问器访问的变量称为属性, 上面的C++ 代码可以用以下Objective-C 来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//.h 
@interface Person : NSObject
{
	int		gender;
	int 	age;
}
@property int gender;
 
-(int) GetAge;
-(void) SetAge:(int) newValue;
@end
 
//.m
@implement	Person
@synthesize gender;
-(int) GetAge
{
	return age;
}
 
-(void) SetAge:(int) newValue
{
	age = newValue;
}
@end

上面的代码中gender就是Person的属性, 如果有对象person则可以通过几种方式读写gender

  1. person.gender = GenderMale 
  2. printf("性别 %d", person.gender) 
  3. [person setGender:GenderMale]; 
  4. printf("性别 %d", [person getGender];

只要申明了属性, 那么就自动拥有get和set访问器,这里很重要的是@synthesize,通过它才可以自动为属性添加访问器,如果自定义了访问器那么@synthesize将不会再次添加。 age变量则需要通过访问函数来存取。

 

待续。。。

iPhone开发之Objective-C学习(4)

Objective-C的内存管理

在Mac OSX 系列操作系统以及iPhone平台上写应用程序时,打开垃圾回收选项,如果程序并不涉及复杂的内存分配, 就几乎可以不用操心内存管理的问题。系统会自动释放部分不用的内存,就像Java那样。 但是如果所编写的程序中有大量内存分配以及频繁释放使用, 这时就需要自己来管理内存。 也就是说,如果你使用alloc方法为对象分配空间, 就应该在使用完后手动发送release消息以释放内存空间。autorelease自动释放类型无需手动发送release消息,否则会使程序崩溃, 系统会退出在autorelease对象作用域时自动释放相应内存空间。如下面的代码中,

1
2
3
4
5
6
7
//自动释放类型的对象, 系统会自动释放其内存空间
NSString* str1 = [NSString string];
 
NSString* str2 = [[NSString alloc] init];
//.. 使用 str2
// 在不使用时发送release消息释放内存空间
[str2 release];

Objective-C的内存管理体系引入一种叫引用计数的概念来管理内存,类似C++ COM对象中的引用计数器,当计数器减小到0 时释放内存空间。 简单来说, 在使用alloc创建对象是引用计数为1, 使用retain一次计数加1, 发送release计数减1,如

1
2
3
4
5
NSString* string = [[NSString alloc] init];//计数为1
[string retain];// 计数为2
//....
[string release];
[string release];// 需要发送release消息两次才能释放内存空间

这里有一张来自http://cocoadevcentral.com 的图很生动的解释了这一原理

内存分配与释放

在平时编写程序是无需去在意引用计数, 只要记住一般情况下只有两种情况下才需要显式发送release消息释放空间
1. 保留变量实例,以供后续使用
2. 函数内创建的临时对象

最后, 记住每使用一次alloc就需要发送release或autorelease消息一次, 每调用一次retain也同样需要release, 只要alloc或者retain 和release或者autorelease成对出现就不会存在内存泄露的可能。

待续…

iPhone开发之Objective-C学习(3)

到现在为止,已经学习了如何调用类方法以及创建对象。 到目前为止我们还没有看到如何才能定义一个类, 上两次的内容已经多次涉及到类及类的成员,现在我们可以学习一下如何才能定义一个自己的类。

设计一个类(接口)

一般来讲创建一个类需要两部分,首先是申明类的头文件ClassName.h, 还有类实现的源文件ClassName.m, 如果你想在程序中混合C/C++编程那么就需要使用.mm或者.M ,这样编译器会以此判断该类中混合了Objective-C 和 C语言。 ClassName.h 头文件中定义类的成员变量以及公有成员函数, 源文件中则包含实际的实现代码,如果你想定义私有函数可以放在实现源文件中,不过需要注意的是必须在该函数被调用调用之前。下面用一个具体的例子来学习如何定义自己的类

1
2
3
4
5
6
7
#import <Cocoa/Cocoa.h>
@interface Friend : NSObject
{
	NSString* 	name;
	int		age;
}
@end

我们从NSObject类继承一个新的类Friend,#import导入Cocoa库的Cocoa.h 头文件, @interface 表示申明一个类定义,也是类定义的开始, 在花括号内是两个成员变量, 最后@end表示类定义结束。对于成员变量可以使用Assessors访问器来访问,也可以申明方法来存取变量

1
2
3
4
5
6
7
8
9
10
11
12
#import <Cocoa/Cocoa.h>
@interface Friend : NSObject
{
	NSString* 	name;
	int		age;
}
 
-(NSString*) getName;
-(int)	getAge;
-(void) setName:(NSString*) newName;
-(void) setAge:(int) newAge;
@end;

可以定义存取的方法,如 setName 和 getName。 再来看看实现文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#import <Cocoa/Cocoa.h>
@implement Friend
-(NSString*) getName
{
	return name;
}
-(int) getAge
{
	return age;
}
-(void) setName:(NSString*) newName
{
	name = newName;
}
-(void) setAge:(int) newAge
{
	age = newAge;
}
-(id) init
{
	if( (self=[super init]) )
	{
		[self setName:@&quot;Mike&quot;];
		[self setAge:22];
	}
	return self;
}
 
-(void) dealloc
{
	[name release];
	[super dealloc];
}
@end;

除了要实现定义的成员函数, 还需要重新实现初始化以及析构函数init 和 dealloc, init中的第一行显示由父类来创建一个类对象付给self, 如果成功则给成员变量赋初值, 然后返回self。 在析构释放内存空间时,先把子类中的所有需要释放的对象都release, 然后发送release消息给父类释放内存。

怎么样,定义新类是不是很简单呢? 这里需要注意的几个问题:

  1. 类定义的开始与结束

    由@interface开始,@end; 结束
  2. 实现类时也需要有开始结束的标致

    @implement表示开始, @end;表示结束
  3. 一般都从NSObject继承定义新类, 否则将需要自己实现初始化以及释放等等代码
  4. 如果垃圾回收功能处于打开状态, dealloc将不会被调用, 这时需要实现finalize方法

 

待续。。。

iPhone开发之Objective-C学习(2)

上次学习了Objective-C的基础知识和函数调用的基本规则, 现在我们在来了解一下新的概念——Accessors,简单意思就是访问器。 在Objective-C中所有的类成员变量默认都是私有的, 你不可能直接访问这些成员变量。你需要用setValue 和 getValue或者value来赋值或者取值,你也可以在申明变量时制定setter和getter,下面是Objective-C1.x的语法格式

1
2
[friend setName:@"Mike"];
value = [friend name];

普通情况下你没必要在取值的时候添加get前缀, 实际上每一次调用[friend name]都会发送get消息给对象friend。

从Mac OSX10.5 开始支持O-C2.0, 在O-C2.0 中你可以使用点(.)来对成员变量(属性)进行赋值和取值操作, 比如

1
2
friend.name = @"Mike";
value = friend.name;

了解了如何访问类成员变量,我们在来看看如何创建一个类对象。 一般情况下可以有两种方式创建类对象, 第一种是调用类的静态成员创建自动释放对象(稍后会介绍)

1
NSString* str = [NSString string];

调用NSString类的 string 方法返回一个自动释放的对象, 这样赋值很简单,不过要注意对象的作用域,后面将详细介绍自动释放对象。另一种方式是直接分配对象并初始化,如

1
NSString* str = [[NSString alloc] init];

这是一个典型的嵌套调用, 这在上次已经介绍过了, 先是[NSString alloc]分配字符串对象空间, 然后调用init方法初始化, 这样创建的对象需要显式释放,也就是需要调用[str release]去释放内存空间。

 

待续。。。

iPhone开发之Objective-C学习(1)

写在前面, 之所以想写点Objective-C相关知识的文章,是因为近1年都在从事苹果及iPhone的开发,其中也走过不少弯路,也从其他网友那获得了很多帮助,所以想把自己的学习心得写出来,以便有需要的朋友作为参考。以下内容均假定阅读者有一定的软件开发经验。

如果想在苹果Mac OSX系统进行开发,Objective-C是最重要的开发语言,现在Apple已经把开发的重点放在了基于Cocoa库的图形界面, 支持C++的Carbon图形库已经让出了主导地位, 而Cocoa库正是应用Objective-C语言开发的。 如果你有C/C++的编程经验, 那么在进行Objective-C的开发将会容易些,因为Objective-C本身就是C/c++的超集, 它包含C/C++的所有特性和支持标准C库, 但其语法本身更优美 简洁,更能体现OO思想也就是面向对象。

在学习Objective-C之前先把Objective-C(以下会以O-C代替)、Cocoa、Carbon以及XCode等几个名词的概念搞清楚, Objective-C是开发语言,前面说过,O-C是c/c++的超集合, Cocoa是在苹果系统上O-C实现的图形开发库相当于windows系统的win32 SDK和MFC, Carbon是早期苹果操作系统上的C/C++图形库也相当于MFC,XCode是个开发集成环境,相当于windows系统上的Visual Stdio系列。

以上介绍了苹果系统开发的基本概念,现在介绍一些Objective-C基础知识,

  • 变量类型
    Objective-C支持C的所有类型,也就是说char,unsigned char,int,long,float,double等均可使用;
    结构类型 如日期的结构定义

    1
    2
    3
    4
    5
    6
    
    struct Date
    {
    	unsigned char day;
    	unsigned char month;
    	unsigned char year;
    };

    其它类型比如枚举、及预定义变量均和c语言用法相同

  • 文件引用、类型导入
    Objective-C中依然可以使用#include来引入其他文件,不过推荐使用#import来导入其它类型,官方文档介绍说这样可以减少出错的几率
  • id类型
    id是Objective-C中的特殊类型, 他指向一个对象,你可以理解为c中的void*
  • 字符串
    Objective-C中可以有c类型的字符串,比如”string”,也可以用NSString类型字符串,一般用@”string”表示, 其中‘@’是将字符串”string”转换为NSString类型

以上是一些基本的语言知识, 其中大多数都和c/c++相同,目前为止除了#import之外,其它的内容对于C/C++开发人员来说都非常熟悉了。

这里先从如何调用类的方法开始说起, 看下面的代码

1
2
[object method];
[object methodWithParamter:param];

没错,Objective-C就是这样进行方法调用的,与C/c++不同的是 ‘[]’的使用, [] 表示对一个类对象的方法进行调用,其中object是类对象, method就是所调用的方法, 你可以调用带有参数的方法,不过在方法名称和参数之间要保留 ‘:’ 来告知编译器如何编译。
方法也可以有返回值,如下

1
2
result = [object methodWithRetValue];
result = [object methodwithPrameterAndRetValue:param];

你也可以这样调用类的方法,比如NSString

1
NSString* string = [NSString string];

这里方法string就是NSString类特殊方法,类似于c++中的静态成员函数

多重方法调用,比如C++ 中的 result = object1.function1 ( object2.function2() );在O-C中可以这样来实现

1
result = [object1 function1:[object2 function2]];

代码中 最外层[]表示object1 调用function1方法,里面的[]表示object2 调用function2所得的结果作为function1的参数传入

多参数方法调用,比如c/c++中的 object.function(arg1, arg2,arg3 );在O-C中就该是这样的
首先是方法申明

1
-(void) function:(int)arg1 secondArg:(float) arg2 thirdArg:(NSString*)arg3;

调用时就是这样的

1
[object function:arg1 secondArg:arg2 thirdArg:arg3];

也就是方法名称后面直接跟参数列表, 其中第一个参数不需要别名,其它参数必须设置别名,O-C使用参数别名还确定所调用参数的,这样编译器才能正确解释,参数之间用1-N个空格分开。

待续。。。

美国电话号码格式化的Objective-C代码

最近在做iPhone上的应用程序, 其中涉及到电话号码, 美国人喜欢自己常用的电话号码格式,就像iPhone拨号程序那样如: 1(234)567-8901这样的11位号码,查了一下iPhone的官方SDK没有找到需要的信息, 只好自己动手写一个简单的格式化函数。美国的电话号码有以下几种规则,比如11位的手机或者带国家代码的电话号码,前面已经提到了,超过11位则按正常的数字显示,不需要加任何格式;还有一种是10位号码,普通的日常应用的是7位电话号码,一般格式为:012-3456,以‘-’隔开前三位和后四位。超过7位的用(012)345-6789来表示,超过10位数字则按正常的数字号码显示,如01234567890. 好了, 知道了规则那么写程序就相对比较简单了, 代码如下

+(NSString*) encodePhoneNumber:(NSString*) phone
{
NSLocale* locale = [NSLocale currentLocale];
if( [[locale localeIdentifier] compare:@"en_US"]!=NSOrderedSame )
return phone;

if( [phone length]==0 )
return phone;
if( [phone rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet] ].location==NSNotFound )
{
const char* string = [phone UTF8String];
int length = [phone lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
if( [[NSString stringWithCString:string length:1] intValue]==1 )
{
if( length > 11 )
return phone;
NSMutableData* array = [[[NSMutableData alloc] init] autorelease];
// 1 (234) 567-8901
for( int i=0; i < length; i++ )
{
if( i==1 )
{
[array appendBytes:" (" length:2];
}
if( i == 4 )
{
[array appendBytes:") " length:2];
}
if( i==7 )
{
[array appendBytes:"-" length:1];
}
[array appendBytes:string++ length:1];
}
return [NSString stringWithUTF8String:(const char*)[array bytes]];
}
else
{
// (012) 345-6789
if( length > 10 )
return phone;
NSMutableData* array = [[[NSMutableData alloc] init] autorelease];
int i=0;
if( length <=7 )
{
for( i=0; i < length; i++ )
{
if( i==3 )
{
[array appendBytes:"-" length:1];
}
[array appendBytes:string++ length:1];
}
}
else
{
for( i=0; i < length; i++ )
{
if( i==0 )
[array appendBytes:"(" length:1];
if( i==3 )
[array appendBytes:") " length:2];
if( i==6 )
[array appendBytes:"-" length:1];
[array appendBytes:string++ length:1];
}
}
[array appendBytes:"\0" length:1];
return [NSString stringWithUTF8String:(const char*)[array bytes]];
}
}
return phone;
}