首页 > 代码库 > objective-c学习笔记(2)

objective-c学习笔记(2)

面向对象和面向过程思想

OC是面向对象的,C是面向过程的。面向对象和面向过程只是解决问题的两种不同思想

面向对象和面向过程的区别

以用电脑听歌为例子

面向过程关注的是解决问题的步骤,数据和操作分离

  • 打开电脑
  • 播放电脑中的歌曲
  • 关闭电脑

面向对象,Everything is an object!一切都是对象,数据和操作不分离,思考解决问题需要多少个对象,不用分析需要多少步骤解决问题

  • 电脑
  • 开机
  • 播放歌曲  
  • 关机

区别分析

  • 面向过程关注的是解决问题需要哪些步骤
  • 面向对象关注的是解决问题需要哪些对象
  • 没有开发经验很难感受到它们的区别,两种思想都能达到解决问题的目的,但是解决思路不一样

现实生活中面向对象的例子

  • 想打电话、发短信 》 找手机,不用分析电话要怎样才能拨通
  • 去饭店吃饭 》 找服务员,不用分析怎么到厨房炒菜
  • 汽车坏了 》 找汽车维修工,不用分析修车的步骤
  • 境界:万物皆对象

  常用术语

  • 面向过程 Procedure Oriented
  • 面向对象 Object Oriented,简称OO
  • 面向对象编程 Object Oriented Programming,简称OOP

类和对象的关系

面向对象中有2个非常重要的概念:类和对象

如何创建对象

1)       面向对象解决问题的时候必须有对象

2)       现实生活的例子:如何创造汽车对象?

  a)       需要先有汽车的建造图纸,图纸上描述清楚汽车应该具备的属性和功能(行为)

  • 属性:轮子数、时速
  • 功能(行为):跑

  b)           然后再根据图纸上的描述生成汽车

  c)           每一辆汽车都是对象,都有自己具体的属性值,都是图纸的实例

  d)           图纸是抽象的,汽车是具体的。图纸是对汽车对象的高度概括

OC中的面相对象

1)       类相当于图纸,用来描述一类事物。也就是说,要想创建对象,必须先有类

2)       利用类来创建对象,对象是类的具体存在

3)       因此,面向对象解决问题应该是先考虑需要设计哪些类,再利用类创建多少个对象 

需要设计哪些类,如何设计类

1)       类的设计,只关心3样东西:

  • 事物名称(类名):人(Person)
  • 属性:身高(height)、年龄(age)
  • 行为(功能):跑(run)、打架(fight)

2)       一般名词都是类

  • 坦克发射3颗炮弹轰掉了2架飞机(设计坦克类,飞机类,炮弹类)
  • 小明在公车上牵着一条叼着热狗的狗(人类,公车类,狗类,热狗类)

3)       拥有相同(或者类似)属性和行为的对象都可以抽像出一个类,把具有相似,或相同属性和行为的对象,高度抽象为类,具有类名、属性、行为

4)       哪个对象最清楚这个行为,就把这个行为写到哪个对象中去。打开电脑(开机)这个行为应该是属于电脑的。

定义OC的类和创建OC的对象

要描述类分2大步骤:类的声明、类的实现(定义)。跟函数类似,函数也分声明和定义。而声明一个类又需要三大要素:类名,属性,行为 

类的声明

1)   代码编写

  • 定义一个Car类,拥有2个属性:轮子数、时速,1个行为:跑
  • 类名\属性的命名规则:标示符的规则
  • 类名的命名规范:有意义、驼峰标识、首字母必须大写
 1 /* 2  类名:Car 3  属性:轮胎个数,时速 4  行为:跑 5 */ 6 //类的声明,关键字@interface后一个空格,跟一个类名,然后最后必须写@end,告诉编译器类声明完毕 7 //类的声明用来声明对象的属性(成员变量,也叫实例变量)和行为(方法) 8 //: NSObject 继承一个类(在Foundation框架里),让car类具备创建对象的能力 9 //自然要加上头文件10 #import <Foundation/Foundation.h>11 12 @interface Car : NSObject13 {//花括号里用来写对象属性,不能写方法14     //@pulic  可以让成员变量被外部指针间接的访问,15     @public16     int wheels;//轮胎个数17     int speed;//时速18 }19 20 //方法(行为)21 //三要素:方法名,参数,返回值(类似函数,分声明和实现),方法的声明在类的声明里,且不能写在花括号里。22 //方法虽然类似c的函数,但是和函数千差万别23 //只要方法是对象的方法,则声明前必须加一个减号-,这是规则!24 //oc方法里的任何数据类型都必须用小括号()括起来25 //oc方法的小括号就一个作用,就是括住数据类型的。故- (void) run();是不对的!26 - (void) run;//ok27 @end28 29 //类的实现,类似于类的声明语法,也要写@end30 @implementation Car31 //oc方法的实现,必须写在类的实现里(类的实现就是为了写方法的实现),说清楚方法里有什么32 - (void) run33 {34     NSLog(@"车子跑起来!");35 }36 @end37 38 int main()39 {40     //利用类创建对象41     //在oc,想执行一些行为,必须写上一个中括号[]42     //[行为执行者 行为名称]43     //执行Car这个类的new行为来创建对象,分配了内存,每个对象都有自己的存储空间来存储自己的成员变量等元素44     //对象里的成员变量,默认初始化为0,wheels是0,speed是045     //[Car new];//创建了一个Car类的对象,返回对象的地址(返回对象)。之后内存里存在这个对象了。46     //oc里想操作对象,只能必须用指针去间接操作!47     Car *p = [Car new];//把地址保存到指针里,p指向的是Car类型的对象(指针占8个字节)48     49     //又创建一个新对象,[Car new];每次都创建新对象50     Car *p1 = [Car new];//默认成员变量值还是051     //给p指向的对象的属性赋值52     p->wheels = 4;53     p->speed = 200;54     55     NSLog(@"车子有%d个轮子,时速是:%d km/h", p->wheels, p->speed);56     57     //[方法执行者 方法名称],想执行一个行为,用中括号58     //给p指向的对象发送一条run消息59     [p run];60     61     //程序退出,内存被回收62     return 0;63 }

 

@public可以让Car对象的wheels和speed属性被外界访问

 

加上:NSObject的目的是让Car类具备创建对象的能力,也需要Foundation头文件

 

main函数的代码分析、内存分析(对象在内存中有成员)

[Car new]每次都会创建出新的对象,并且返回对象的地址,那么就应该用一个指针变量保存对象的地址

Car *c = [Car new];//用一个指针变量c指向内存中的Car对象     

设置车子对象的属性,跟用指向结构体的指针访问结构体属性一样,用->

c->wheels = 3;

c->speed = 300;

创建多个Car对象

分别只设置wheels、speed属性

Car *c1 = [Car new];

c1->wheels = 4;

Car *c2 = [Car new];

c2->speed = 250;

[c1 run];//对c1对象发消息,和c2无关

 

1个赋值给另一个,然后修改属性

Car *c1 = [Car new];

c1->wheels = 4;

c1->speed = 250;

Car *c2 = c1;

c2->wheels = 3;

[c1 run];//指针c2也指向了指针c1指向的对象,故唯一的这个对象的wheels改变为3,speed不变。

 1 /* 2  3  类名:Person 4  属性:whight,age(oc里叫实例变量,或成员变量) 5  行为:走路(oc里叫方法) 6  */ 7 #import <Foundation/Foundation.h> 8  9 //1、类的声明10 //写成员变量,和类的方法声明11 @interface Person : NSObject12 {13     //实例变量14     @public15     int age;16     double weight;17 }18 //方法声明,对象的方法必须-开头,数据类型必须()括起来19 - (void)walk;20 21 @end22 23 //2、类的实现24 //写方法的实现25 @implementation Person26 - (void) walk27 {28     NSLog(@"%d岁, %.2f斤 的人开始走路", age, weight);//自动换行29 }30 @end31 32 int main()33 {34     Person *person = [Person new];35     person->age = 20;36     person->weight = 100.0;37     [person walk];//给指针person指向的人对象发送walk消息,告诉该对象调用属于这个对象的walk方法,这是oc的消息机制38     39     Person *person1 = [Person new];//又创建一个新的对象,用指针person1指向它,它和之前的对象完全没有关联,是开辟的新的内存空间40     person1->age = 24;41     person1->weight = 150;42     [person1 walk];43     44     person1 = person;//指针person1指向了第一个对象(person指针指向的对象)45     46     return 0;47 }

对象在内存里的变化和状态图

 

典型失误:oc类属性,默认是protected,外部无法访问,需要手动设置为public。还有一个典型的错误,oc千万不能想当然的和c++,java混淆,不用在类实现里再添加花括号了,直接写方法的实现即可。

 

和c++的不同,oc的类占据一份内存空间!在第一次使用类的时候,类被加载到内存里,即在创建对象之前,先给类分配内存空间。

 

注意:

1存放类的内存只被加载一次(第一次使用对象的时候加载对象属于的类)即可,且里面只存放方法的列表。

2内存里每个对象的存储空间内部默认都有一个指针叫isa指针,每个对象都有。

作用是:指向这个对象所对应的类(存放类的内存块),所以,所有的对象都共用一份方法,所以,类只被加载一次即可。成员变量每个对象都有自己的那一份内存,但是方法就共用一份内存

3调用方法的过程:

[person1 walk]; 执行:给指针person1指向的对象发送一条walk消息,去调用那个对象的walk方法,然后对象会顺着isa指针找到对应的类,去类里找方法,找到walk方法,就前往对应的代码去执行,就在walk方法里访问当前对象的成员变量age和weight(因为成员变量,每个对象都有自己的一份)

面向对象封装的好处

  • 更加接近人类的思考方式
  • 只需要关注对象,不需要关注步骤 

oc的对象与函数的关系

  • 对象成员变量作为函数参数
  • 指向对象的指针作为函数参数
  • 修改指针指向对象的成员
  • 修改指针的指向
 1 #import <Foundation/Foundation.h>//NSObject 2 @interface Car : NSObject 3 { 4     //花括号里才能写成员变量 5     @public 6     int wheels; 7     int speed; 8 } 9 - (void) run;10 @end11 12 @implementation Car13 - (void) run14 {15     NSLog(@"%d个轮子的车速是%d,跑起来了!", wheels, speed);16 }17 @end18 //oc的函数和c的函数还是比较相似的,但是方法是方法,函数是函数,要区分开来!19 //oc方法和函数是有本质区别的20 void test(int w, int s)21 {22     w = 3;23     s = 100;24 }25 26 void test1(Car *newC)27 {28     newC->wheels = 3;29 }30 31 void test2(Car *newC)32 {33     Car *c2 = [Car new];34     c2->wheels = 5;35     c2->speed = 300;36     newC = c2;//这里实际上把参数newC指针指向的地址覆盖了!!!!故不会再影响外面的对象37     newC->wheels = 6;38 }39 40 int main()41 {42     Car *c = [Car new];43     c->wheels = 4;44     c->speed = 200;45     //把刚创建的对象的成员变量值,传递给函数46    // test(c->wheels, c->speed);47    // [c run];//给对象传递run的消息48     /*49      打印结果是4个轮子的车速是200,跑起来了!50      因为test函数参数是简单的值传递,故不会改变原来的值。51      */52     53     //test1(c);54    // [c run];55     /*56      此时打印:3个轮子的车速是200,跑起来了!57      */58     59     test2(c);60     [c run];61     /*62      打印4个轮子的车速是200,跑起来了!63      */64     65     return 0;66 }

test2(c);

[c run];//打印4个轮子的车速是200,跑起来了!

这段代码在内存里是这样的:指针c指向的是函数外部的对象,开始执行方式test2,给形参newC分配内存空间,newC也指向了c指向的函数外部的对象,转到对应函数代码去执行,函数内部(局部变量)创建新的对象,用新指针c2指向,然后修改对象对应的成员变量值,关键还有一步,newC指针最后指向了函数内部创建的对象,newC = c2; newC不再指向函数外部那个对象了,故不论newC指向的对象对成员变量做如何改变,对外部对象没有影响。并且,函数执行完毕,作为局部变量,存储newC的内存消失,存储c2的内存消失。但是注意:oc的对象不会自动去回收,一旦创建,一直存在内存里,除非手动释放,或者程序执行完毕。所以,函数创建的对象不会消失。但是没有指向它的指针存在了。

 

objective-c学习笔记(2)