首页 > 代码库 > 黑马程序员_ Objective-c 面向对象笔记详解

黑马程序员_ Objective-c 面向对象笔记详解

1)类,对象,方法

类名:

1) 类名的第一个字母必须是大写

2) 不能有下划线

3) 多个英文单词,用驼峰标识

类的声明和实现

类的声明

@interface 类名 : NSObject

{

                  @public

                  成员变量;

}

方法声明;

@end

类的实现

@implementation 类名

方法实现;

@end

举例说明:

 

 view plaincopy
 
  1. //Horse类的声明  
  2. @interface Horse : NSObject  
  3. {  
  4.     @public //使成员变量可以让外部访问  
  5.       
  6.     //定义成员变量color,weight  
  7.     charchar *color;  
  8.     int weight;  
  9. }  
  10. //方法声明(方法前必须加减号’-’且数据类型必须加括号())  
  11. - (void)eat;  
  12. @end  
  13.   
  14. //类的实现  
  15. @implementation Horse  
  16.   
  17. - (void)eat  
  18. {  
  19.     NSLog(@"%s色,体重为%d的马吃草,",color,weight);  
  20. }  

常见错误:OC语言编译时与C语言相同,一样是从上到下顺序编译,所以如果 类的声明和实现写在后面会报错,可以将类声明单独提到调用前的位置,也可将类声明和实现都提上去

 

对象

对象的创建

 

 view plaincopy
 
  1. //创建一个Horse类的对象s  
  2. Horse *s=[Horse new];  
  3.   
  4. //给对象s的属性的赋值,用符号:->  
  5. s->color="red";  
  6. s->weight=200;  
  7.   
  8. <pre name="code" class="objc">//使用对象s调用方法eat  
  9. [s eat];  

 

1) 在OC中,要调用对象,就必须使用指针

创建对象:类名 *p=[类名 new];

 

view plaincopy
 
  1. //创建一个Horse类的对象s  
  2. Horse *s=[Horse new];  

 

匿名对象:[[类名 new] 对象方法];红色部分即为匿名对象

 

view plaincopy
 
  1. //创建并使用匿名对象调用eat方法  
  2. [[Horse new] eat];  

 

 

OC语言中,对象分配内存后,系统并不自动回收,直到程序结束或手动回收

2) 在OC中,要执行一些行为(方法),就必须写上一个中括号[行为执行者 行为名称]

 

 view plaincopy
 
  1. //使用对象s调用方法eat  
  2. [s eat];  

 

方法

方法即对象的行为

1) 方法:方法名、参数、返回值(同样是声明和实现)

2) 只要是OC对象的方法,必须以减号’-’开头

3) OC方法中任何数据类型都必须用小括号()扩住

方法的声明和实现

1) 有返回值无参数的方法

声明:

 

[objc] view plaincopy
 
  1. - (int)eat;   //返回int类型  

 

实现:

[objc] view plaincopy
 
  1. - (int)eat  
  2. {  
  3.      方法体;  
  4. }  

2) 带参数且有返回值的方法

  • 带一个参数

声明:

 

[objc] view plaincopy
 
  1. - (double) squre:(double)number;  

 

实现:

[objc] view plaincopy
 
  1. - (double) squre:(double)number  
  2. {  
  3.     方法体;  
  4. }  
  • 带多个参数

声明:

 

[objc] view plaincopy
 
  1. -(double)sumOfNum1:(double)number1 andNum2:(double)num2;  

 

实现:

[objc] view plaincopy
 
  1. -(double)sumOfNum1:(double)number1 andNum2:(double)num2  
  2. {  
  3.     方法体;  
  4. }  

解读:

 

view plaincopy
 
  1. - (double)sumOfNum1:(double)number1andNum2:(double)num2;  

 

方法前减号’-’:表明方法类型,对象方法为减号’-‘

减号后double:表示返回数据类型

(sumOfNum1:   andNum2:)括号里为方法名,注意包括冒号:

冒号后double:表示参数类型

number1:表示参数名

方法调用

[对象指针 方法名];

如:[c sumOfNum1:10 andNum2:21];

方法总结:

OC方法中,一个参数对应一个冒号

冒号:也是方法名的一部分

方法中有多个参数时,要有多个冒号,且官方标准冒号前应该多写变量注释,即方法名尽量详细描述方法功能

封装

封装基本介绍

set方法

作用:提供一个方法给外界设置成员变量的值,可以在方法里面对参数进行相应过滤

命名规范:

1) 方法名必须以set开头

2) set后面跟上成员变量的名称,成员变量首字母必须大写

3) 返回值一定是void

4) 一定会接受一个参数,且参数类型跟成员变量类型一致

5) 形参名称不能跟成员变量一样

get方法

作用:返回对象内部的成员变量

命名规范:

1) 一定有返回值,返回值类型一定与成员变量类型一致

2) 方法名跟成员变量类型一致(区别于其他语言以get开头,苹果官方不建议如此)

3) 不会接受参数

封装的好处

实现成员变量的只读(即:可以只提供get方法)

成员变量的命名规范

命名规范:一定要以下划线_开头

作用:

1) 让成员变量和get方法的名称区分开

2) 可以跟局部变量区分开,看到下划线开头的变量,一般即为成员变量

弱语法

OC在运行过程中才会检测对象是否实现相应的方法(区别于C语言在链接时检测)

OC语言中,当类和对象方法的声明以及实现在main()函数前面时:

1) 类声明可以缺失,仅报warning

2) 方法声明也可以缺失,正常运行

注:声明在main()前,实现在main()后市,缺失会直接报错

类方法

基本使用

1) 类方法以加号’+’开头

2) 直接用类名调用

类方法与对象方法

对象方法

1) 减号’-’开头

2) 只能由对象调用

3) 对象方法中能访问当前对象的成员变量(实例变量)

类方法

1) 加号’+’开头

2) 只能由类(名)来调用

3) 类方法中不能访问成员变量(实例变量)

类方法的好处和使用场合

好处:

1) 不依赖于对象,执行效率高

2) 能用类方法,尽量用类方法

使用场合:当方法内部不需要使用到成员变量 时,就可以改为类方法

工具类

工具类:基本没有成员变量,里面的方法基本都是类方法的类

self(本质是一个指针)

self概念:指向当前方法调用者(在对象方法中指向当前调用对象,在类方法中指向当前类)

格式:

[self 方法名];

使用时注意死循环(方法内部不能用self调用本身)

继承

基本使用

OC中继承用冒号’:’

继承的好处

1) 抽取重复代码

2) 建立了类之间的关系

3) 子类拥有父类中的所有成员成员变量和方法

重写:

子类重新实现父类中的某个方法,覆盖以前的做法

使用注意:

1) 父类必须声明在子类的前面

2) 子类不能拥有和父类相同的成员变量

3) 调用某个对象方法时,优先去当前对象中找,如果找不到,去父类中找

继承和组合

继承:A是B(类)

组合:A拥有B(类)即:B类为A类的成员变量

继承-super

super的作用

1) 直接调用父类中的某个方法

2) Super在对象方法中,那么就会调用父类的对象方法;super在类方法中时,那么就会调用父类的类方法

3) 使用场合:子类重写父类的方法时想保留父类的一些行为的时候

多态(父类指针指向子类对象)

基本使用

动态绑定:调用方法时会检测指向的真实对象

多态的好处

当多个函数调用多个子类的相同对象方法时,可以利用多态将多个函数写为一个函数

多态的局限性

局限性:不能用父类类型的指针直接调用子类特用的方法(会报warning,可通过强制类型转换后使用)

强制类型转换:

 

[objc] view plaincopy
 
  1. Animal *a=[Dog new];  
  2. //强制将Animal类型的指针a转换为Dog类型的指针a并赋值给d  
  3. Dog *d=(Dog *)a;  

 

多态总结

1) 没有继承就没有多态

2) 代码体现:父类类型的指针指向子类对象

3) 好处:如果函数/方法参数中使用的是父类类型,既可以传入父类对象,又可以传入子类对象

4) 局限性(同上)

开发技巧

NSSting(NSString是一个字符串类)

基本使用;字符串输出时,格式输出符为’%@’

作业讲解

1.使用类定义对象及参数的时候注意星号’*’。

2.经验写法:方法返回值为 BOOL类型时,方法名一般都以is开头。

3.当类成员变量为对象时,在为这个成员变量初始化赋值时,必须先创建对象并赋值,然后调用set方法将对象传递给该类的对象成员变量。

多文件开发

1. 定义一个类分2个文件:.h声明文件、.m实现文件

.h:包含成员变量、方法的声明(即类声明)

.m:包含方法的实现

2. 如果要使用某一个类,只需要#import类的.h文件即可。

Xcode功能演示

1. Xcode断点调试功能

即:可以在程序代码中任意行设置任意个断点调试程序,可实现代码逐行执行,并能查看执行结果。

2. Xcode代码段保存功能

即:可以将复用频率高的代码块保存起来以便以后直接调用。

长按左键实现

3. Xcode注释标记功能

#pragma mark 注释语句(或作为书签标记用)

对后面的一个方法进行注释

 #pragma mark –注释语句

加‘-’ 后Xcode会将后面所有的方法进行注释,直到遇到下一个加‘-’ 的注释,这样即可实现代码的分类注释。

4. Xcode多文件同时查看功能

Xcode可以同时查看多个文件。

如:同时查看.h和.m文件。

核心语法

点语法(编译器特性)

1. 点语法基本使用

本质:点语法本质是调用set和get方法。

2. 点语法使用注意

Person *p=[Person new];

OC中点语法:

p.age=10就等同于[p setAge:10]调用set方法

Int a=p.age等同于[p age]调用get方法

使用过程中set方法和get方法表示上都为p.age,具体调用哪个方法编译器会。通过判断是否赋值区别

由于点语法为方法调用,使用过程中注意不要在方法内使用点语法调用本身方法,会造成死循环

成员变量的作用域

1. OC中,成员变量的作用域分以下四种:

@public (公开的)在有对象的前提下,任何地方都可以直接访问。

@protected (受保护的,默认情况下就是受保护的)只能在当前类和子类的对象方法中访问

@private (私有的)只能在当前类的对象方法中才能直接访问

@package (框架级别的)作用域介于私有和公开之间,只要处于同一个框架中就可以直接通过变量名访问

2.  成员变量作用域使用注意

OC中没有类声明,只有类实现,也可以定义一个类。(知道即可,一般没人这样写),且定义在类实现implementation中的成员变量默认为私有的,即时加上@public也不能在任何地方访问,因为其他文件只导入.h文件,在其他文件中这些成员变量是不可见的(除非类实现implementation写在了main()函数的前面,这时main()函数可以调用)。

类实现implementation中定义成员变量时,不能重复定义声明中的成员变量。

@property和@synthesize

 @property

Xcode编译器中使用@property可以自动生成成员变量的set和get方法的声明。

如:成员变量为:int _age;

则@property int age ;语句就表示同时声明了setAge和getAge方法,等价于:

[objc] view plaincopy
 
  1. - (void)setAge:(int)age;  
  2. - (int)age;  

解读@property int age ;

int位置为所要声明的成员变量的数据类型

age位置为所要声明的set方法中传入的形参名称

@synthesize

Xcode编译器中使用@sythesize可以自动成员变量的set和get方法的实现。

如:成员变量为:int age;

则@synthesize age=_age;语句表示同时实现了set和get方法,等价于:

 view plaincopy
 
  1. - (void)setAge(int)age  
  2. {  
  3.            _age=age;  
  4. }  
  5.   
  6. - (int)age  
  7. {  
  8.            return  _age;  
  9. }  

 

解读@synthesize  age = _age;

=等号左边的age表示生成声明为age的方法

=等号右边的_age表示访问_age成员变量

@property和@synthesize的最简写法

Xcode4.2以后版本呢,编译器支持一句@property同时完成-成员变量在声明中的定义-成员变量set和get方法的声明-成员变量set和get方法的实现。

如:@interface Car:NSObject

       @property int speed;

       @end

       @implementation Car

       @end

则以上代码可正常运行,编译器会自动生成-成员变量在声明中的定义(自动生成_speed变量,但自动生成的变量为私有的private)-成员变量set和get方法的声明-成员变量set和get方法的实现。

使用细节

@synthesize细节

@synthesize speed=_speed;

生成的实现方法访问_speed变量

@synthesize speed;

生成的实现方法默认访问speed变量,如果没有speed变量,编译器会自动生成speed变量,且生成的speed变量默认为private类型

当类中已存在方法实现时,编译器不会生成对应的方法,且如果类中set和get方法同时存在时,编译器将不会自动生成speed变量

@property细节

默认情况下,自动生成的set和get方法访问带下划线_的成员变量

万能指针-id

OC中,id为万能指针,可以指向任何对象。

本质:id相当于(NSObject *)

 

[objc] view plaincopy
 
  1. id a=[Car new];     //定义了一个指向车对象的指针a  

 

构造方法

1. 基本概念

构造方法:用来初始化对象成员变量的方法,是一个对象方法。

构造方法init存在于NSObject类中

2. 重写构造方法和自定义构造方法

  • 重写构造方法:

目的:为了让对象一创建出来,成员变量就有一些固定的值

Person类中:

[objc] view plaincopy
 
  1. - (id) init  
  2. {  
  3.         //重写父类NSObject中init方法前,必须先调用父类init方法初始化父类中的一些成员变量和其他属性  
  4.         if(self=[super init])  
  5.         {  
  6.                 _age=10;  
  7.         }  
  8.         return self;  
  9. }  
  • 自定义构造方法:

目的:可以在自定义一些值,使对象一创建出来,成员变量就拥有这些值

Person中:

[objc] view plaincopy
 
  1. //自定义初始化方法,使人对象一创建出来,就拥有名字和年龄  
  2. - (id)initWithName:(NSString *) name andAge:(int) age  
  3. {  
  4.          //必须先调用[super init];  
  5.          if(self=[super init])  
  6.          {  
  7.                   _name=name;  
  8.                   _age=age;  
  9.          }  
  10.          return self;  
  11. }  
  • 子类自定义构造方法

Student中(此类继承Person类,_name及_age变量继承之Person,_no为Student自身变量):

[objc] view plaincopy
 
  1. //自定义初始化方法,使学生对象一创建出来,就拥有名字、年龄和学号  
  2. - (id)initWithName:(NSString *) name andAge(int) age andNo(int)no  
  3. {  
  4.          //调用父类的initWithName: andAge方法,将传进来的name和age交给父类处理  
  5.          if(self=[super initWithName: name andAge: age])  
  6.          {  
  7.                   _no=no;  
  8.          }  
  9.          return self;  
  10. }  

总结:谁的成员变量,调用谁的自定义构造方法进行初始化

分类(Category)

分类作用:在不改变原来类内容的前提下,为类增加一些方法

基本介绍

分类定义:

//声明

@interface 类名(分类名称)

 

@end

//实现

@implementation 类名(分类名称)

 

@end

[objc] view plaincopy
 
  1. //创建类Person的分类  
  2. #import "Person.h"  
  3. //分类声明  
  4. @interface Person (PersonOther)  
  5.   
  6. @end  
  7.   
  8. #import "Person+PersonOther.h"  
  9. //分类实现  
  10. @implementation Person (PersonOther)  
  11.   
  12. @end  

分类使用注意:

  • 分类只能增加方法,不能增加成员变量

  • 分类方法实现中可以访问原来类中声明的成员变量(除private外都可访问)(编程测试是否能访问@property编译自动生成的成员变量---已测不能访问)

  • 分类可以重新实现原来类中的方法,但是会覆盖调原来的方法,导致原来方法无法使用(一般不建议这样写)。

  • 编译运行时方法调用优先级:分类->原来类->父类

  • 一个类有多个分类时,优先级由编译器编译顺序决定

利用分类给系统自带的类增加方法

目前学到的系统的类有:NSString、NSObject

例:给NSSring添加类方法和对象方法

 

[objc] view plaincopy
 
  1. //给NSString添加计算字符串中数字个数的对象方法和类方法  
  2. #import <Foundation/Foundation.h>  
  3.   
  4. @interface NSString (NSStringOther)  
  5. //对象方法声明  
  6. - (int)stringOfNumCount;  
  7. //类方法声明  
  8. + (int)stringOfNumCount:(NSString *)str;  
  9. @end  
  10.   
  11. #import "NSString+NSStringOther.h"  
  12.   
  13. @implementation NSString (NSStringOther)  
  14.   
  15. //对象方法实现  
  16. - (int)stringOfNumCount  
  17. {  
  18.     int count=0;  
  19.     for (int i=0; i<self.length; i++) {  
  20.         if ([self characterAtIndex:i]>=‘1‘&&[self characterAtIndex:i]<=‘9‘) {  
  21.             count++;  
  22.         }  
  23.     }  
  24.     return count;  
  25. }  
  26.   
  27. //类方法实现  
  28. + (int)stringOfNumCount:(NSString *)str  
  29. {  
  30.     int count=0;  
  31.     for (int i=0; i<str.length; i++) {  
  32.         if ([str characterAtIndex:i]>=‘1‘&&[str characterAtIndex:i]<=‘9‘) {  
  33.             count++;  
  34.         }  
  35.     }  
  36.     return count;  
  37. }  
  38. @end  

 

注意:

OC中字符串@”zhang123”就是一个对象,可以[@”zhang123” 对象方法]直接调用对象方法

类的本质

  • 类的本质:类本身也是一个对象,是一个Class类型的对象,简称类对象
  • 类的深入研究类的加载和初始化

程序一旦启动,就会加载项目中所有的类和分类(加载:自我认为是给类分配内存空间?),而且加载后会调用所有类和分类的+load方法

当第一次使用某个类时,就会调用当前类的+initialize方法(只有第一次会调用,只调用一次)

总是先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)一定发生

总是先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的initialize方法)用才初始化,当然如果用子类则父类也一定会先初始化,只用父类时,子类并不初始化

黑马程序员_ Objective-c 面向对象笔记详解