1)类,对象,方法
类
类名:
1) 类名的第一个字母必须是大写
2) 不能有下划线
3) 多个英文单词,用驼峰标识
类的声明和实现
类的声明
@interface 类名 : NSObject
{
@public
成员变量;
}
方法声明;
@end
类的实现
@implementation 类名
方法实现;
@end
举例说明:
- //Horse类的声明
- @interface Horse : NSObject
- {
- @public //使成员变量可以让外部访问
- //定义成员变量color,weight
- charchar *color;
- int weight;
- }
- //方法声明(方法前必须加减号’-’且数据类型必须加括号())
- - (void)eat;
- @end
- //类的实现
- @implementation Horse
- - (void)eat
- {
- NSLog(@"%s色,体重为%d的马吃草,",color,weight);
- }
常见错误:OC语言编译时与C语言相同,一样是从上到下顺序编译,所以如果 类的声明和实现写在后面会报错,可以将类声明单独提到调用前的位置,也可将类声明和实现都提上去
对象
对象的创建
- //创建一个Horse类的对象s
- Horse *s=[Horse new];
- //给对象s的属性的赋值,用符号:->
- s->color="red";
- s->weight=200;
- <pre name="code" class="objc">//使用对象s调用方法eat
- [s eat];
1) 在OC中,要调用对象,就必须使用指针
创建对象:类名 *p=[类名 new];
- //创建一个Horse类的对象s
- Horse *s=[Horse new];
匿名对象:[[类名 new] 对象方法];红色部分即为匿名对象
- //创建并使用匿名对象调用eat方法
- [[Horse new] eat];
OC语言中,对象分配内存后,系统并不自动回收,直到程序结束或手动回收
2) 在OC中,要执行一些行为(方法),就必须写上一个中括号[行为执行者 行为名称]
- //使用对象s调用方法eat
- [s eat];
方法
方法即对象的行为
1) 方法:方法名、参数、返回值(同样是声明和实现)
2) 只要是OC对象的方法,必须以减号’-’开头
3) OC方法中任何数据类型都必须用小括号()扩住
方法的声明和实现
1) 有返回值无参数的方法
声明:
- - (int)eat; //返回int类型
实现:
- - (int)eat
- {
- 方法体;
- }
2) 带参数且有返回值的方法
- 带一个参数
声明:
- - (double) squre:(double)number;
实现:
- - (double) squre:(double)number
- {
- 方法体;
- }
- 带多个参数
声明:
- -(double)sumOfNum1:(double)number1 andNum2:(double)num2;
实现:
- -(double)sumOfNum1:(double)number1 andNum2:(double)num2
- {
- 方法体;
- }
解读:
- - (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,可通过强制类型转换后使用)
强制类型转换:
- Animal *a=[Dog new];
- //强制将Animal类型的指针a转换为Dog类型的指针a并赋值给d
- 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方法,等价于:
- - (void)setAge:(int)age;
- - (int)age;
解读@property int age ;
int位置为所要声明的成员变量的数据类型
age位置为所要声明的set方法中传入的形参名称
@synthesize
Xcode编译器中使用@sythesize可以自动成员变量的set和get方法的实现。
如:成员变量为:int age;
则@synthesize age=_age;语句表示同时实现了set和get方法,等价于:
- - (void)setAge(int)age
- {
- _age=age;
- }
- - (int)age
- {
- return _age;
- }
解读@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 *)
- id a=[Car new]; //定义了一个指向车对象的指针a
构造方法
1. 基本概念
构造方法:用来初始化对象成员变量的方法,是一个对象方法。
构造方法init存在于NSObject类中
2. 重写构造方法和自定义构造方法
- 重写构造方法:
目的:为了让对象一创建出来,成员变量就有一些固定的值
Person类中:
- - (id) init
- {
- //重写父类NSObject中init方法前,必须先调用父类init方法初始化父类中的一些成员变量和其他属性
- if(self=[super init])
- {
- _age=10;
- }
- return self;
- }
- 自定义构造方法:
目的:可以在自定义一些值,使对象一创建出来,成员变量就拥有这些值
Person中:
- //自定义初始化方法,使人对象一创建出来,就拥有名字和年龄
- - (id)initWithName:(NSString *) name andAge:(int) age
- {
- //必须先调用[super init];
- if(self=[super init])
- {
- _name=name;
- _age=age;
- }
- return self;
- }
- 子类自定义构造方法
Student中(此类继承Person类,_name及_age变量继承之Person,_no为Student自身变量):
- //自定义初始化方法,使学生对象一创建出来,就拥有名字、年龄和学号
- - (id)initWithName:(NSString *) name andAge(int) age andNo(int)no
- {
- //调用父类的initWithName: andAge方法,将传进来的name和age交给父类处理
- if(self=[super initWithName: name andAge: age])
- {
- _no=no;
- }
- return self;
- }
总结:谁的成员变量,调用谁的自定义构造方法进行初始化
分类(Category)
分类作用:在不改变原来类内容的前提下,为类增加一些方法
基本介绍
分类定义:
//声明
@interface 类名(分类名称)
@end
//实现
@implementation 类名(分类名称)
@end
- //创建类Person的分类
- #import "Person.h"
- //分类声明
- @interface Person (PersonOther)
- @end
- #import "Person+PersonOther.h"
- //分类实现
- @implementation Person (PersonOther)
- @end
分类使用注意:
-
分类只能增加方法,不能增加成员变量
-
分类方法实现中可以访问原来类中声明的成员变量(除private外都可访问)(编程测试是否能访问@property编译自动生成的成员变量---已测不能访问)
-
分类可以重新实现原来类中的方法,但是会覆盖调原来的方法,导致原来方法无法使用(一般不建议这样写)。
-
编译运行时方法调用优先级:分类->原来类->父类
-
一个类有多个分类时,优先级由编译器编译顺序决定
利用分类给系统自带的类增加方法
目前学到的系统的类有:NSString、NSObject
例:给NSSring添加类方法和对象方法
- //给NSString添加计算字符串中数字个数的对象方法和类方法
- #import <Foundation/Foundation.h>
- @interface NSString (NSStringOther)
- //对象方法声明
- - (int)stringOfNumCount;
- //类方法声明
- + (int)stringOfNumCount:(NSString *)str;
- @end
- #import "NSString+NSStringOther.h"
- @implementation NSString (NSStringOther)
- //对象方法实现
- - (int)stringOfNumCount
- {
- int count=0;
- for (int i=0; i<self.length; i++) {
- if ([self characterAtIndex:i]>='1'&&[self characterAtIndex:i]<='9') {
- count++;
- }
- }
- return count;
- }
- //类方法实现
- + (int)stringOfNumCount:(NSString *)str
- {
- int count=0;
- for (int i=0; i<str.length; i++) {
- if ([str characterAtIndex:i]>='1'&&[str characterAtIndex:i]<='9') {
- count++;
- }
- }
- return count;
- }
- @end
注意:
OC中字符串@”zhang123”就是一个对象,可以[@”zhang123” 对象方法]直接调用对象方法
类的本质
- 类的本质:类本身也是一个对象,是一个Class类型的对象,简称类对象
- 类的深入研究---类对象的使用
利用类对象调用class方法创建类
例:Person类
Class c=[Person class]; 则:c现在就等价于Person类
注意:Class本身就包含星号 *
也可以利用Person的实例对象调用class方法创建类
例:Person *p=[[person alloc] init];
Class c1=[p class]; 则:c1现在也等价于Person类
- 类的深入研究---类的加载和初始化
程序一旦启动,就会加载项目中所有的类和分类(加载:自我认为是给类分配内存空间?),而且加载后会调用所有类和分类的+load方法
当第一次使用某个类时,就会调用当前类的+initialize方法(只有第一次会调用,只调用一次)
总是先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)一定发生
总是先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的initialize方法)用才初始化,当然如果用子类则父类也一定会先初始化,只用父类时,子类并不初始化