对象的存储细节
2015-07-16 12:02 另十 阅读(292) 评论(0) 编辑 收藏 举报
分析这句代码在内存中的存储细节:
Person *p = [Person new];
第一步:先把Person类的代码(属性和方法)加载到代码区(只会加载一次,内存里面只有一份代码)
第二步:代码执行到[Person new],
[Person new] 做了3件事情
1) 申请内存空间
new 的时候申请的空间在内存的堆区(程序动态分配的内存空间)
2)给实例变量初始化
如果实例变量是基本数据类型,此时给初始化为0
如果 。。。。OC字符串类型 null
3) 返回空间的首地址
同时在堆内存中分配一个isa指针,每一个对象都包含一个isa指针.这个指针指向当前对象所属的类。
第三步: p(指针变量) 存放在栈区,指向堆内存的首地址(注意这个地址不是isa存的对象所属的类)
修改实例变量就是找到指针p,然后修改它指向的属性
[p run];
首先找p对应的堆区的空间,然后找到 _isa指针,再找到_isa指向的
代码区的空间,然后到该空间中找 方法
[Person new] 做了3件事情
1) 申请内存空间
2)给实例变量初始化
3) 返回空间的首地址
1、申请的空间在内存的哪个区?
new 的时候申请的空间在内存的堆区(程序动态分配的内存空间)
当new的时候内存的布局是这么样的
初始化的时候:
如果实例变量是基本数据类型,此时给初始化为0
如果 。。。。OC字符串类型 null
2、实例变量又保存在什么地方
堆区
p(指针变量) 存放在栈区
3、对象方法保存在什么地方
代码区
4、为什么使用 [p run]; 就可以调用方法了 ?如何调用的
首先找p对应的堆区的空间,然后找到 _isa指针,再找到_isa指向的
代码区的空间,然后到该空间中找 方法
5、一个类可以创建多个对象
代码:
#import <Foundation/Foundation.h> @interface Person : NSObject { @public int _age; float _weight; NSString *_name; } //行为 -(void)run; @end @implementation Person -(void)run{ NSLog(@"人正在跑"); } @end int main(int argc, const char * argv[]) { @autoreleasepool { //创建对象 Person *p = [Person new]; p->_name = @"柯南"; p->_age = 13; //_age 0 //_name null NSLog(@"姓名:%@,年龄:%d,体重:%f",p->_name,p->_age,p->_weight); [p run]; //又创建了一个对象p1 Person *p1 = [Person new]; p1->_name = @"贝娜"; p1->_age = 33; NSLog(@"姓名:%@,年龄:%d,体重:%f",p1->_name,p1->_age,p1->_weight); [p1 run]; } return 0; }
2015-07-16 11:56:04.569 03-对象的存储细节[699:38284] 姓名:柯南,年龄:13,体重:0.000000 2015-07-16 11:56:04.570 03-对象的存储细节[699:38284] 人正在跑 2015-07-16 11:56:04.570 03-对象的存储细节[699:38284] 姓名:贝娜,年龄:33,体重:0.000000 //体重是没有赋值的,所以就根据类型默认值 2015-07-16 11:56:04.570 03-对象的存储细节[699:38284] 人正在跑
5-函数和对象方法的区别
函数和对象方法的区别
对象方法:
-(void)run;
(1)对象方法的实现只能写在@implementation...@end中,对象方法的声明只能写在 @interface...@end中间
(2)对象方法都以-号开头,类方法都以+号开头
(3)对象方法只能由对象来调用,类方法只能由类来调用,不能当做函数一样调用
(4)函数属于整个文件,可以写在文件中的任何位置,包括@implementation...@end中,但写在 @interface...@end会无法识别,函数的声明可以再main函数内部也可以在main函数外部。
(5)对象方法归类\对象所有
函数: void run(){
} (1)所有的函数都是平行的
(2)函数不存在隶属关系
(3)使用的时候可以直接调用
(4)不可以访问对象中的成员变量
【掌握】06-常见错误
常见错误:
(1)@interface @end和@implementation @end不能嵌套包含
(2)只有类的声明没有类的实现
只有@interface没有@implementation时,程序编译能够通过,但是执行报错 ,所以除了你要把这个方法定义成私有方法时(没声明,有实现)外,必须同时有@interface,@implementation
(3)漏写@end
(4)两个类的对象声明顺序(可以把顺序打乱) ,但声明必须在在实现前
(5)成员变量没有写在{}里
(6)方法的声明写在了{}里面
(7)在声明时,请注意成员变量不能脱离对象而独立存在
(8)方法无法像函数那样的调用
(9)成员变量和方法不能用static等关键字修饰,不要和c语言混淆
(10)类的实现可以写在mian函数后面,在使用之前只要有声明就可以
(11)
语法检查上没有问题,因为编译器发现你已经声明了,运行时时错误的
'-[Person run]: unrecognized selector sent to instance 0x100103410' 不能向实例发送消息,即是找不到方法
这个错误会让程序停在那,不会退出
这个错误可以扑捉
#import <Foundation/Foundation.h> @interface Car : NSObject { @public int _lunzi; } -(void)stop; @end int main(int argc, const char * argv[]) { @autoreleasepool { Car *car = [Car new]; @try { //有可能会出错的代码 [car stop]; //语法检查上没有问题,运行时时错误的 } @catch (NSException *exception) { //错误的处理方法 NSLog(@"出错了,您调用的方法没有实现!"); NSLog(@" %@ ",exception); //打印出错误的信息 } @finally { printf("xxxxxx\n"); } } return 0; } @implementation Car @end
2015-07-16 14:14:15.714 06-常见错误汇总[852:56541] -[Car stop]: unrecognized selector sent to instance 0x100301990 2015-07-16 14:14:15.716 06-常见错误汇总[852:56541] 出错了,您调用的方法没有实现! 2015-07-16 14:14:15.716 06-常见错误汇总[852:56541] -[Car stop]: unrecognized selector sent to instance 0x100301990 xxxxxx
-对象和方法之间的关系
对象和方法之间的有二种关系
一)对象作为方法的参数
二)对象作为方法的返回值
对象和方法之间的关系 1)对象作为方法的参数 // 方法名 形参数类型 形参数名 -(void)dispPerson:(Person *) person; Person *p1 = [Person new]; [p dispPerson:p1] //对象作为方法的实参 2)对象作为方法的返回值
#import <Foundation/Foundation.h> // 0 1 2 typedef enum{kSexMan,kSexWomen,kSexYao} Sex; //定义个person类 @interface Person : NSObject { @public NSString *_name; Sex _sex; } //对象作为方法的参数 -(void)dispPerson:(Person *) person; //对象作为方法的返回值 -(Person *)changSex:(Person*) person; @end @implementation Person //对象作为方法的参数 -(void)dispPerson:(Person *) person{ NSLog(@"姓名:%@,性别:%d",person->_name,person->_sex); } //对象作为方法的返回值 p1 -(Person *)changSex:(Person*) person{ //修改姓名 person->_sex = kSexWomen; return person; //p1 } @end int main(int argc, const char * argv[]) { @autoreleasepool { //创建对象p Person *p = [Person new]; //创建对象p1 Person *p1 = [Person new]; p1->_sex = kSexYao; p1->_name = @"刷我的卡"; Person *p2 = [Person new]; p2->_name = @"张三丰"; p2->_sex = kSexWomen; [p dispPerson:p2];
//修改性别 //[p changSex:p1]; Person *p3 = [p changSex:p1]; //p3 p1 都指向同一个空间 NSLog(@"姓名:%@,性别:%d",p3->_name,p3->_sex); } return 0; }
2015-07-16 15:10:04.581 07-对象和方法之间的关系[882:65770] 姓名:张三丰,性别:1 2015-07-16 15:10:04.581 07-对象和方法之间的关系[882:65770] 姓名:刷我的卡,性别:1
补充:
import有两个作用:
一是和include一样,完完全全的拷贝文件的内容;
二是可以自动防止 文件内容的重复拷贝(即使文件被多次包含,也只拷贝一份)。
在使用命令行进行编译链接文件的时候,通常是把.m文件单文件编译,然后再把所有的目标文件 链接,
但是在Xcode中,是把所有的.m文件都进行编译链接的,如果出现重复定义的错误,那大部 分问题根源应该就是文件内容被重复包含或者是包含.m文件所引起的。
源文件中不论是使用include还是import,都不能包含.m或者是.c文件,只能放声明。因此,在OC 中通常把类拆分开来,拆分成声明和实现两个部分。