版权声明:原创作品,谢绝转载!否则将追究法律责任。
对象发送和接受消息
尽管有不同的方法来发送消息在对象之间,到目前位置是想中括号那样[obj doSomeThing];左边是接受消息的接收器,右边是接收器调用的方法,换句话说obj发送doSomeThing消息。前面讲了怎么创建类的接口:
@interface MyClass:NSObject
- (void)doSomeThing;
@end
怎么在实现文件里面实现方法呢?
@implementation MyClass
- (void)doSomeThing
{
NSLog(@“hello,world”);
}
@end
然后只要你创建了这个对象就可以像这样发送消息
[obj doSomeThing];
为了指定消息的接收者。最重要的是怎么理解指针怎么在Objective-c应用对象。
怎么用指针来跟踪对象:
C和Objective-c利用变量来跟踪值,就像其他语言。
像C语言的基本类型
int someInterger = 42;
float someFloatingPointNumber = 3.14f;
本地变量也就是局部变量在方法中定义一样就像:
- (void)myMethod
{
int someInteger = 42;
}
范围有限,定义在方法里面
在这个例子中,someInteger 是定义在方法里的局部变量,一旦括号结束了那么他也就消失了,那么他的值也就消失了。
Objective-c的对象,和之前的对比,分配略有不同,对象的生命周期可能比局部变量长一点。特别是对象的存活周期要比实例变量长一点创建类跟踪他,因此对象的内存是动态分配和销毁的。
注意了:本地变量是在栈上的,对象是在堆上的。
你需要用C指针他带有内存地址,来跟踪他们在内存的位置。如下:
- (void)doSomeThing
{
NSString *myString - // get frome somewhere...
}
虽然这个指针变量在这个方法内。这个实际的字符对象指向内存这个也许有更长的生命周期。也许他已经存在,或者你可以在方法里把他们传递例如:
你需要传递一个对象当发送消息的时候。你的方法的参数有一个对象,这是个对象指针。上节都是没有参数的:
- (void)someMethodWithVaule:(SomeType)value;
如下我定义一个带字符串参数的方法
- (void)saySomeThing:(NSString *)greeting;
你可以在实现文件实现这个方法:
- (void)saySomeThing:(NSString *)greeting
{
NSLog(@“%@”,greeting);
}
这个字符串对象像一个局部变量一样被限制在方法里,但是方法结束后他还存在,因为他是之前存在的方法调用返回的。所以他在方法完成后会继续存在。
注意:NSLog()用格式说明符表示替换的标记,就像C标准库里的printf()功能。如果被提供的对象里面有descriptionWithLocale:方法或者description方法存在。这个description方法被NSObject对象实现返回这个对象的类内存地址等详细信息,有些类可以重载他提供很多有用的信息。例如NSString这个方法,他的description方法用来返回他被传入的字符串
方法可以返回值:
就像用方法的参数传递值一样,方法也可以提供返回值。void方法是没有返回值的。
- (int)returneSomeThing;
在实现里面这样写:
- (int)returneSomeThing
{
returne 77;
}
这个方法除了返回一个值没有别的作用如下调用也没有错[someobj returneSomeThing];
如果你需要跟踪这个返回值,你定义一个变量来跟踪他。
你还可以返回一个对象比如在NSString方法里提供的uppercaseString方法
- (NSString *)uppercaseString;
就像上面那样可以弄个指针来跟踪他的结果。
NSString *str = @"hello, qiqi!";
NSString *returneStr = [str uppercaseString];
当这个方法返回的时候returneStr 将要指向代表HELLO QIQI !代表的对象。
记得我们实现方法返回一个对象像这样:
- (NSString*)returnString
{
NSString *StringToReturn = //create an string;
returne StringToReturn;
}
这个对象将要继续存在当返回这个值的时候虽然指针已经超出了这个范围。
有一些内存管理要考虑的情况:一个返回的对象(被创建在堆上)需要足够的存活时间被其他的方法调用,但是不能永恒因为这样会造成内存泄漏。arc会为照顾你这样的情况。
对象可以发送消息给他们自己:
当你写一个方法实现的时候,你有机会隐藏重要的值,self ,概念的说,self是个指针,就像greeting值,可以调用方法在当前的接受对象。例如:
@implementation XYZPerson
- (void)sayHello {
[self saySomething:@"Hello, world!"];
}
- (void)saySomething:(NSString *)greeting {
NSLog(@"%@", greeting);
}
@end
对象可以调用父类的方法
还有另一个重要的关键字在Objective-c叫super,发送消息给super 是一个调用父类方法的方式。super最常见的是重载方法。
比如我创建了一个新的类然后这个新类要用到之前那个类的方法这样你就可以调用之前的方法了。
对象是动态创建的:
Objective-c对象是动态创建的,第一步创建对象保证内存有足够的内存不仅仅为的是能定义属性在类里也为了能定义属性在父类里。
这个NSObject根类提供了类方法,alloc给你提供:
+(id)alloc;注意返回的类型是id的,这是个特殊关键字在Objective-c里意味着任意类型。是一个指针指向一个对象,就像NSObject*但是特殊的英文他不使用星号。
alloc的另一个任务是清理对象的内存把他们之前有可能的属性清理掉,但是还不够必须还得初始化对象才完整。
这个init方法是用来确保他的属性当创建的时候有合适的初始值。他返回的也是id。
不要把分配和初始化分两行。
初始化方法可以带参数:
一些对象需要初始化用所需要的值。这个NSNumber对象,例如必须创建的时候带有参数:
- (id)initWithBool:(int)value;
NSNumber *magicNumber = [[NSNumber alloc] initWithInt:77];
类的工厂方法代替了分配和初始化
NSNumber *number= [NSNumber numberWithInt:42];
这个效果和上一个实例方法的初始化是一样的。
我们用New创建一个对象如果不需要参数初始化:
我们也可以创建实例用new方法,这个方法是NSObject提供的并且不需要在自己的类里面重载这个方法。
NSObject *obj = [NSObject new];
NSObject *obj = [[NSObject alloc]init];
上面两种效果是一样的。
字面值常量:提供一种简约的文字创建格式
NSString *str = @"qiqi";
同样的效果我们可以创建初始化一个NSString用他的类工厂方法:
NSString *str = [NSString stringWithString@“qiqi”];
NSNumber *myBOOL = @YES;
Objective-c是动态语言
就像之前说的,我们需要用一个指针来跟踪在内存中的对象,因为Objective-c的动态性特性,但是没关系,因为不管你的指针是什么特殊类型,正确的方法都会发送给正确的对象,当你发送消息的时候。这个id类型定义了通用的对象指针,在声明变量的时候我们可以用id指向它,但是你编译的时候并不知道他是什么类型的
想想下面的代码:
id someObj = @"qiqi";
[someobj removeAllObjects];
在这个例子中someObj将要指向NSString类型,但是编译器不知道这个对象是什么类型的,然而这个方法属于集合类的类型例如NSMutableArray,因此编译器不会编译警告或者错误,但是在运行时候出现了一个异常,因为NSString没有这个方法。
现在我们重新修改下:
NSString *someObj = @"qiqi";
[someobj removeAllObjects];
意味着这个编译器将要出现一个错误因为这个方法没有在NSString的接口定义。
因为一个对象的类型在运行的时候才能确定,所以在定义变量的时候无所谓是什么类型的。
之前的代码
XYZPerson *firstPerson = [[XYZPerson alloc] init];
XYZPerson *secondPerson = [[XYZShoutingPerson alloc] init];
[firstPerson sayHello];
[secondPerson sayHello];
尽管这两个对象firstPerson 和 secondPerson都是XYZPerson的静态对象,在运行时候second将要指向XYZShoutingPerson对象。当方法sayHello调用的时候,正确的实现将要被使用,对second,这意味着XYZShoutingPerson版本。
确定对象是不是平等的:
你需要确定一个对象是不是和另一个对象一样,重要的要记住你要使用的是指针,标准的c == 运算符测试两个实例变量是不是相等
if(someInterger ==42)
{
}
当处理对象时候==是用来测试两个单独的指针是不是指向同一个对象。
而isEqual是用来表示两个对象代表的内容是不是一样的。这个方法是NSObject的。
==测试的是内存地址 isEqual测试的是内容 散列表的值 hash。
如果你需要比较两个对象的多少,i你不能用标准的C比较大小> <然而基本的foundation类型像NSNumber NSString NSDate 提供了比较的方法。
例如:
if ([someDate compare:another] == NSOederedAscending)
{
}
对空对象操作:
你一直是定义标准变量的时候初始化他们否则他们的初始值将要包含垃圾从之前的堆栈中。
但是对指针对象不需要因为编译器自动的把他置为空如果你不指定其他的初始值。
因为Objective-c是允许你发送消息给他nil值的因为向Objective-c对象发送消息是什么都不会发生的。
如果你想nil发送消息他会返回0如果又返回值,返回的结构值都是0
if (somePerson != nil) {
// somePerson points to an object
}
if (somePerson) {
// somePerson points to an object
}
if (somePerson == nil) {
// somePerson does not point to an object
}
if (!somePerson) {
// somePerson does not point to an object
}