第一讲 OC简介及基本语法
Objective-C简称OC是在C语言的基础上,增加了一层最小的面向对象语法,完全兼容C语言,也就是可以在OC代码中混入C语言代码,甚至是C++代码。可以使用OC开发Mac OS X平台和IOS平台的应用程序。简单的介绍了一下OC,下面我们来看看OC的基本语法,学习OC之前我们先学习了C语言,因为OC是在C语言的基础上的一门开发语言,因此OC的很多基本语法跟使用方法跟C语言有类似的地方但是也有其独特的地方。
1. 关键字
OC中的关键字基本上所有的都是以@开头,但也有少数不是以@开头的,下面是一些较常用的关键字:
@interface、@implementation、@end @public、@protected、@private、@selector @try、@catch、@throw、@finally @protocol、@optional、@required、@class @property、@synthesize、@dynamic self、super、id、_cmd、__block、__strong、__weak、
2. 字符串以@开头
比如@"Hello"是OC中的字符串,而"Hello"则是C语言中的字符串
3. OC程序的开发过程
OC程序的开发跟C语言类似,从 .m源文件编译成 .o目标文件再链接成 a.out可执行文件
4. 程序框架
OC程序的入口也是main函数
在编写第一个OC程序时用到了OC的输出函数NSLog,但调用NSLog需要包含Foundation框架,OC中一般使用#import <Foundation/Foundation.h>来包含Foundation框架,每个框架都有自己的主头文件:即最主要的头文件。主头文件名字一般跟框架名称一样,包含了框架中的所有其他头文件,Foundation框架的主头文件名称就是Foundation.h,只需要包含Foundation框架的主头文件,就可以使用整个框架的东西。
其中#import的作用:跟C语言中#include一样,用来拷贝某个文件的内容,#import可以自动防止文件内容被拷贝多次,也就意味着头文件中不用加入相应的预处理指令。
#import <Foundation/Foundation.h>
//OC程序的入口:main函数
int main()
{
//printf("第一个OC程序 ");//OC完全兼容C语言程序
NSLog(@"第一个OC程序"); //NSLog输出内容会自动换行
return 0;
}
5. NSLog与printf的区别
NSLog接收OC字符串作为参数,printf接收C语言字符串作为参数
NSLog输出后会自动换行,printf输出后不会自动换行
使用NSLog需要#import <Foundation/Foundation.h>
使用printf需要#include <stdio.h>
6. Foundation框架的作用
开发OC、iOS、Mac程序必备的框架
此框架中包含了很多常用的API(应用编程接口)
框架中包含了很多头文件,若想使用整个框架的内容,包含它的主头文件即可:#import <Foundation/Foundation.h>
7. BOOL的使用
BOOL类型的本质 typedef signed char BOOL;
BOOL类型的变量有2种取值:YES、NO
#define YES (BOOL)1
#define NO (BOOL)0
BOOL的输出(当做整数来用)
NSLog(@"%d %d", YES, NO);
第二讲 类和对象
OC是一门面向对象的开发语言,而C语言是面向过程的,因此在开发思想上要把面向过程和面向对象好好区分开来,体会其中的不同之处。面向过程关注的是解决问题需要哪些步骤,而面向对象关注的是解决问题需要哪些对象。
1. 类的设计
在C语言中完整的写一个函数需要函数的声明和定义(也就是实现),而OC中类似,完整的写一个类需要类的声明和实现
类的设计主要包括:类名,属性和行为
设计类名注意点:
类名的第一个字母必须是大写
不能有下划线
多个英文单词,用驼峰标识
2. 方法(行为)的设计
OC中方法就是行为,主要包括方法名,参数,返回值(声明和实现)方法不能放在大括号里面
注意点:只要是OC对象的方法,必须以减号 - 开头,类方法以+开头
OC方法中任何数据类型都必须要用()扩住
OC方法中的小括号():只有一个作用,用来扩住数据类型
3. 类的声明跟实现
OC中类的声明值得是用来声明对象的属性跟行为,声明对象的属性(实例变量或者叫成员变量) , 成员变量默认情况下会做一个初始化,所有成员变量默认都是0
声明在@interface和@end之间进行,实现在@implementation和@end之间进行
下面我们来通过一个具体实例创建一个类并引出一些知识点跟注意点:
#import <Foundation/Foundation.h> // 因为使用了NSObject
@interface Car : NSObject // NSObject目的是:让Car这个类具备创建对象的能力
{
@public // @public关键字,可以让外部的指针间接访问内部的成员变量
int wheels; // 轮胎个数
int speed; // 时速 xxkm/h
// 大括号里面只能写属性不能写行为
}
- (void)run; // 跑这个方法
@end
//类的实现 用来实现@interface中声明的方法
@implementation Car
- (void)run
{
NSLog(@"车子跑起来了!"); // 实现声明的方法
}
@end
int main()
{
//[Car new];会创建出一个新对象,并且会返回新对象本身(新对象的地址)
Car *p = [Car new]; // 定义了一个指针变量p,p将来指向的是Car类型的对象
Car *p2 = [Car new]; // [Car new]每次都会创建出一个新的对象
p->wheels = 4; // 给p所指向的wheels属性赋值,类似于结构体
p->speed = 250;
// 给p所指向的对象发送一条run消息,消息机制:给指针所指向的对象发送一条run消息
[p run];
[p2 run];
NSLog(@"车子有%d个轮子,时速为%dkm/h",p->wheels,p->speed);
return 0; // 程序退出后会默认把内存回收
}
[Car new]在使用类创建对象之前,会将类加载进内存,类的内存里面只放方法列表,创建的每个对象内部默认有一个指针(isa指针),这个指针指向这个对象所对应的类,所有的对象共用相同的类里面的方法。
类的声明跟实现常见错误:
只有类的声明,没有类的实现
漏了@end ,@interface和@implementation嵌套
两个类的声明嵌套
成员变量没有写在括号里面
方法的声明写在了大括号里面
语法细节:
成员变量不能在{}中进行初始化、不能被直接拿出去访问
方法不能当做函数一样调用
成员变量方法不能用static等关键字修饰,别跟C语言混在一起(暂时忽略)
类的实现可用写在main函数的后面,主要在声明后面就行了
4. 方法跟函数的区别
方法:
对象方法都是以减号-开头
对象方法的声明必须写在@interface和@end之间
对象方法的实现必须写在@implementation和@end之间
对象方法只能由对象来调用
对象方法归类对象所有
函数
函数能写在文件中的任意位置(@interface和@end之间除外),函数归文件所有,函数可以定义在@implementation和@end之间,这个是没有问题完全可以
函数调用不依赖于对象
函数内部不能直接通过成员变量名访问某个对象的成员变量
5. 方法的声明和实现
@interface JiSuanQi : NSObject
- (double)pi; // 方法名叫pi,不带参数的方法
// OC方法中,一个参数对应一个冒号
// 方法名叫pingFang: ,要连上冒号,为了防止方法名的冲突,冒号也是方法名的一部分
- (int)pingFang:(int)num; // 带一个参数的方法
// 方法名叫: sumWithNum1:andNum2:
- (int)sumWithNum1:(int)num1 andNum2:(int)num2; // 带两个参数的方法,可读性好 冒号前面加一些描述信息,来描述后面的参数是干嘛用的
@end
因此注意在定义方法名时要注意一些规范,保证可读性好,类似于 sumWithNum1:andNum2:这种的方法名。
6. 方法的练习
下面通过一个练习体会一下OC的方法的声明跟实现,以及需要注意的地方,方法的命名需要格外注意:
// 设计一个方法,用来和其他车比较车速,返回车速的差距
#import <Foundation/Foundation.h>
@interface Car : NSObject // 类的声明
{
@public
int speed; // 车速
}
// 此处传递一个车进来比较速度,车是一个对象,OC中的对象都是指针类型的,数据类型为Car*
- (int)compareSpeedWithOther:(Car *)other;
@end
@implementation Car // 类的实现
- (int)compareSpeedWithOther:(Car *)other
{
// speed当前这辆车的速度
// other->speed 是other传进来比较的这辆车的速度
// 返回当前这辆车和other这辆车的速度差距
return speed - other->speed;
}
@end
int main()
{
Car *c1 = [Car new]; // 创建车对象c1
c1->speed = 300; // 给对象的speed属性赋值
Car *c2 = [Car new]; // 创建对象c2
c2->speed = 280;
int a = [c2 compareSpeedWithOther:c1]; // c2调用方法并传入c1参数进行速度比较
NSLog(@"%d",a); // 打印速度差距
return 0;
}
第三讲 三大特性
第三讲我们主要讲OC的三大特性,OC是一门面向对象的语言,面向对象的开发语言一般共同的特点就是具有三大特性:封装,继承和多态。下面我们来学习一下OC的三大特性。
一、 封装
封装就是对类中的一些字段,方法进行保护,不被外界所访问到,有一种权限的控制功能。
封装的好处:过滤不合理的值,屏蔽内部的赋值过程,让外界不必关注内部的细节。
1. set方法和get方法
set方法
作用:提供一个方法给外界设置成员变量值,可以在方法里面对参数进行相应过滤
命名规范:
(1)方法名必须以set开头
(2)set后面跟上成员变量的名称,成员变量的首字母必须大写
(3)返回值一定是void
(4)一定要接收一个参数,而且参数类型跟成员变量类型一致
(5)形参的名称不能跟成员变量名一样
get方法
作用:返回对象内部的成员变量
命名规范:
(1)肯定有返回值,返回值类型肯定与成员变量类型一致
(2)方法名跟成员变量名一样
(3)不需要接收任何参数
2. 成员变量的命名规范:一定要以下划线 "_" 开头
作用:
让成员变量和get方法的名称区分开
可以跟局部变量区分开,一看到下划线开头的变量,一般都是成员变量
3. 经典错误
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
@implementation Person
@end
int main()
{
Person *p = [Person new];
// OC是在运行过程中才会检测对象有没有实现相应的方法
[p test];//实现中没有test方法
return 0;
}
报错:-[Person test]: unrecognized selector sent to instance 0x7fd2ea4097c0
给Person对象发送了一个不能识别的消息:test
4. 类方法和对象方法
(1)对象方法:
*减号 - 开头
*只能由对象来调用
*对象方法中能访问当前对象的成员变量(实例变量)
(2)类方法:
*加号 + 开头
*只能由类(名)来调用
*类方法中不能访问成员变量(实例变量)
(3)类方法的好处和使用场合:
*不依赖于对象,执行效率高
*能用类方法尽量用类方法
*场合:当方法内部不需要使用到成员变量时,就可以改为类方法
*可以允许类方法和对象方法同名
5. self关键字
self关键字是个指针,self指向方法调用者,代表着当前对象,当成员变量和局部变量同名时,采取就近原则,访问的是局部变量,用self访问成员变量,区分同名的局部变量
self用途:
(1)谁调用了当前方法,self就代表谁,(指向了当前对象-方法调用者)
* self出现在对象方法中,self就代表对象
* self出现在类方法中,self就代表类
(2)在对象方法中利用“self->成员变量名”访问当前对象内部的成员变量
(3)[self 方法名] 调用当前对象的某一个方法,可以调用其他对象方法或者类方法
常见错误:
*低级错误:用self去调用函数
*类方法中用self调用对象方法,对象方法中用self调用类方法
*self死循环
二、 继承
继承是类中的一个重要的特性,他的出现使得我们没必要别写重复的代码,可重用性很高。继承的一些专业术语:父类超类:superclass 子类:subclasssubclasses
1.继承的好处:
*抽取重复代码
*建立了类之间的关系
*子类拥有父类中的所有成员变量和方法
*注意点:基本上所有类的根类是NSObject
2. 方法的重写
重写:子类重新实现父类中的某个方法,覆盖父类以前的做法
注意:
*父类必须声明在子类的前面,实现可以放在子类的后面
*子类不能拥有和父类相同的成员变量
*调用某个方法时,优先去当前类中找,如果找不到,去父类中找
*坏处:耦合性太强:类之间的关系太紧密了,当某个父类不见了,子类就用不了
3. 继承的使用场合
当两个类拥有相同属性和方法的时候,就可以将相同的东西抽取到一个父类中
当A类完全拥有B类中的部分属性和方法时,可以考虑让B类继承A类
// 动物类的声明
@interface Animal : NSObject // 基本上所有的类根类是NSObject
{
double _weight; // 体重成员变量
}
- (void)setWeight:(double)weight; // set方法
- (double)weight; // get方法
@end
@implementation Animal // 方法的实现,这里主要是get和set方法实现
- (void)setWeight:(double)weight
{
_weight = weight;
}
- (double)weight
{
return _weight;
}
@end
@interface Dog : Animal // Dog类继承了动物类
{
double _height; // Dog类完全拥有Animal类的成员变量和方法,并有子类自己的成员变量
}
@end
@implementation Dog
@end
4. 继承和组合
当某个类想拥有另一个类当中的东西,考虑两种方式,一种是继承一种是组合
继承:xx 是 xxx 代表什么什么(子类)是什么什么(父类)
组合:xxx 拥有 xxx
类A
{
int _age;
int _no;
}
类B
{
A *_a; // B里面拥有A,这个是组合
int _weight;
}
在实际的使用中,要注意逻辑和设计,区分好继承和组合的使用。
5. super关键字
super的作用和使用场合:
*直接调用父类中的某个方法
*super处在对象方法中,那么就会调用父类的对象方法
*super处在类方法中,那么就会调用父类的类方法
*使用场合:子类重写父类的方法时想保留父类的一些行为
三、 多态
多态指的是某一类事物的多种形态,OC对象具有多态性
多态的体现:Person *p = [Student new]; p->age = 10; [p walk];
1. 多态的使用注意
*没有继承就没有多态
*代码的体现:父类类型的指针指向子类对象
*好处:如果函数方法参数中使用的是父类类型,可以传入父类,子类对象
*局限性:父类类型的变量 不能 直接调用子类特有的方法。必须强制转为子类类型的变量后,才能直接调用子类特有的方法。
2. 代码中的注意点
Animal *a = [Dog new];
//[a run];run方法为Dog独有,不能直接访问
Dog *d = (Dog *)a;//强制转换为Dog *类型才能调用run方法
[d run];
本章学习总结:
本章主要学习了面向对象的一门开发语言Objective-C。本章第一讲主要学习了OC的一些基本语法,主要包括关键字,字符串,程序框架,注意OC的字符串以@开头,要注意NSLog和C语言printf的区别。本章第二讲主要学习了类和对象,在OC中,类和方法的设计有很多规范和需要注意的地方,养成一种良好的编程习惯是很重要的,这一讲要注意类的声明跟实现的一些注意点,要区分OC的方法跟函数,了解二者分别有什么作用以及使用场合,要注意在声明和实现方法时带参数的情况,注意命名的规范(要有意义而且通顺连贯)。本章第三讲主要学习了OC的三大特性,封装,继承和多态。封装主要讲的是set和get方法,注意set和get方法的命名规范和使用注意,有时根据需求要求只读的话可以很好的利用set和get方法。还学习了类方法和对象方法,要注意二者的使用场合以及调用情况,在一些实际情况中巧妙的互相调用会让程序精简很多。此外还学习了self关键字,谁调用了当前方法,self就代表谁,注意避免一些self的常见错误。第三讲的第二大内容是继承,要了解继承的好处以及使用场合,继承中子类可以重写父类方法,要了解重写的使用注意,特别需要注意继承和组合,二者有什么不同,在实际应用开发中要区分开来,此外还学习了super关键字,了解了其作用和使用场合。第三部分学习了OC的第三大特性多态,注意多态是基于继承的,要了解多态的好处和它的局限性。