黑马程序员——OC语言基本语法知识(一)

时间:2023-02-18 21:01:56
 
 
*** 封装 ***
一、 set方法

通过 指针->成员变量名 方式给成员变量赋值具有危险性, 可能被赋值为不合理的数值。不允许通过指针直接修改成员变量, 就要去掉@public。 通过方法来修改成员变量的值, 方法中可以加代码保证接收的值是合理的赋值。

 

设置成员变量属性值的方法, 通常称为该属性的set方法, 命名方式为 setAge: , 接收一个相同类型的参数,形参的名称不能和成员变量名相同。

 举例:

 
  1. - (void)setAge:(int)newAge   
  2. {  
  3.         // 对传进来的参数值进行过滤, 保证数据安全性  
  4.         if (newAge <= 0)  
  5.                 newAge = 1;  
  6.   
  7.         // 把参数值赋给成员变量  
  8.         age = newAge;  
  9. }  
  10.    


 

在 main函数中调用set方法:

[stu setAge:18];    // 赋值为18

[stu setAge:-18];   // 默认赋值为1

 

以后就不要写@public了, 必须要通过set方法来设置成员变量。 可以保证成员变量数据的合理性。

 

二、 get方法

 

没有@public, 我们就不能通过 stu->age 来查看成员变量的值 (被保护)。我们要通过调用方法来返回成员变量值。

 

get方法: 返回该对象的成员变量值。

 举例

 
  1. - (int) age   
  2. {  
  3.         return age;  
  4. }  
  5.    


 

在main函数中调用get方法获得age属性的值:

int myAge = [stu age];

 

注意: 不是所有的成员变量都有set和get方法, 如果有的成员变量是只读属性(read only), 只能被访问, 不能被修改, 这样的情况就可以只提供get方法, 不写set方法。

 

三、 封装的好处

封装可以保证数据的安全性。 如果要给成员变量赋值, 必须通过set方法进行访问, 在set方法中, 可以添加对不合理的属性值的过滤。

 

四、 命名规范

 

在get方法中, 方法名和返回的成员变量名是一样的, 可读性不好。 所以规范成员变量名以下划线开头, 便于和get方法名和局部变量名区分。

 

成员变量名规范以 

  1. @interface Student : NSObject  
  2. {  
  3.         int _age;      // 规范的的成员变量名  
  4. }  
  5. @end  
  6.    
  7. - (void) setAge:(int)age   
  8. {  
  9.         _age = age;    // 这样set方法的形参名就可以和成员变量同名了(没有下划线)  
  10. }  
  11. - (int) age    
  12. {  
  13.         return _age;  
  14. }  
  15.    
  16. // 调用是相同的  
  17. [stu setAge:18];  
  18. int myAge = [stu age];  


 

*** 继承 ***

 

一、 基本概念

类B继承了类A, 那么类B具有类A的所有属性和方法。

在OC中继承关系用 : 表示。

比如我们要写一个Dog类和一个Cat类, 两个类拥有相似的成员变量和方法, 不想把代码复制很多遍。可以写一个Animal类, 把猫和狗相同的内容放到Animal里, 然后让Dog和Cat继承Animal类。

 

二、 优缺点

继承的好处: 子类拥有父类的所有成员变量和方法, 减少重复代码. 建立类之间的关系。

 

继承的缺点: 代码耦合性太强 (类之间的关系太紧密, 如果某个类坏了, 另一个类会受影响)。

 

我们的类如果不继承NSObject就没有new方法, 就没有创建对象的能力。我们的类能够调用new方法, 说明NSObject类拥有new方法。可以查看NSObject类的说明, 找到 +new 方法。

NSObject是基类, 几乎所有的类最终都是继承于它。也有的类不是继承NSObject的, 比如NSProxy, 它也是一个基类。

 

子类有自己的成员变量方法和父类的所有成员变量和方法 (以及父类的父类的)。

 

*** 多态 ***

有继承才有多态。

多态就是可以用父类的指针指向子类的对象. 不管用什么指针, 调用方法时调用的都是对象的方法。

 

一、 多态的好处:

 

可以使用父类指针来代表各种子类对象调用函数,节省代码。

 

比如, 我们有一个Cat类, 有eat方法; 还有一个Dog类, 也有eat方法

 
  1. @interface Cat : Animal  
  2. - (void) eat;  
  3. @end  
  4.    
  5. @implementation Cat  
  6. - (void) eat   
  7. {  
  8.         NSLog(@"Cat is eating");  
  9. }  
  10. @end  


 

  

我们想写函数来喂动物, 喂Dog和Cat由于参数类型不同, 需要对每种类型都写一个函数:

 


 
  1. void feed(Dog *d)   
  2. {  
  3.         [d eat];  
  4. }  
  5. void feed2(Cat *c )    // 不允许同名函数  
  6. {  
  7.         [c eat];  
  8. }  
  9. int main()   
  10. {  
  11.         Dog *d = [Dog new];  
  12.         feed (d);      // 喂狗  
  13.         Cat *c = [Cat new];  
  14.         feed2 (c);    // 喂猫  
  15.         return 0;  
  16. }  


 

 

这两个函数体是很相似的, 而且如果有更多的动物, 还要写很多相似的函数, 很麻烦, 还要使用不同的名字。

这样,就可以使用多态来简化,写一个Animal类, 作为Dog 和Cat的父类, 这样在函数中就可以使用Animal *指针, 来指代Dog或Cat类型的参数:

 


 
  1. void feed(Animal *a)     // a既可以是Dog, 也可以是Cat, 也可以是其它Animal  
  2. {  
  3.         [a eat];         // 调用对象的eat方法  
  4. }  
  5. int main()   
  6. {  
  7.         Dog *d = [Dog new];  
  8.         feed (d);        // 调用的是Dog的eat方法  
  9.         Cat *c = [Cat new];  
  10.         feed (c);        // 调用的是Cat的eat方法  
  11.         Animal *a = [Animal new];  
  12.         feed (a);  
  13. }  


 

这样只需要写一个函数, 很方便, 而且调用的还都是每个对象自身的方法。

 

二、 多态的局限性

 

不建议用父类指针调用子类的特有方法。

如果用父类指针调用子类在父类中没有的方法, 虽然调用的是子类对象的方法, 但是编译器会报警告, 因为它只能看到用父类的指针调用一个父类没有的方法。

举例

  1. @implementation Animal  
  2. @end  
  3. @implementation Dog  
  4. - (void) run { ... }  
  5. @end  
  6. int main()   
  7. {  
  8.         Animal *a = [Dog new];  
  9.         [a run];  
  10.         return 0;  
  11. }  
  12. 可以正确运行, 但是编译器会警告。  
  13. 如果必须要这么写, 规范方法是进行强制类型转换:  
  14. int main()   
  15. {  
  16.         Animal *a = [Dog new];  
  17.         Dog *d = (Dog *)a;  
  18.         [d run];  
  19.         return 0;  
  20. }