---------------------- Java培训、Android培训、iOS培训、.Net培训,期待与您交流! ---------------------
一、OC的简单认识
1. OC与C
OC是全称Object-C,是在C语言的基础上增加了一层最小的面向对象语法。
OC完全兼容C语言,可以在OC代码中混入C语言代码,甚至C++代码。
OC可以用来开发Mac OS X平台和IOS平台的应用程序。
2. OC关键字
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
OC中的字符串也都是@“字符串”的形式。
3. 数据类型
基本数据类型:
C语言的基本数据类型适用于OC中,如字符型char、整型int、浮点型float/double等等
但是OC类型多了一个布尔型数据类型:BOOL(YES/NO)。
BOOL b1 = YES;
BOOL b2 = NO;
BOOL b3 = 1; //YES
BOOL b4 = 0; //NO
</pre><h2><span style="font-family:SimHei;font-size:18px;font-weight: normal;"> 4. OC的简单使用</span></h2><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"><p><span style="font-family:SimSun;font-size:12px;">(1)跟C语言一样,OC程序的入口函数依然是main函数。OC源程序被写到了一个.m文件中。</span></p></blockquote><p></p><pre name="code" class="objc">//OC程序的入口:main函数
int main()
{
return 0;
}
(2)OC程序运行过程:
1》编写OC源程序:.m .c
2》编译:cc -c xxx.m xxx.c
3》链接:cc xxx.o xx.o -framework Foundation(只有用到Foundation框架才需要引入)
4》运行:./a.out
(3)Foundation框架头文件的路径
1》右击Xcode.app --> 显示包内容
2》Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/Foundation.framework
Xcode模板修改路径:
/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates
* File Templates文件模板:可以修改类文件等
* Project Templates 项目模板:可以修改一些项目描述
(4)Foundation框架
#import <Foundation/Foundation.h>
只需要包含Foundation框架的主头文件,就可以使用整个框架的东西。
#import的用途:
1》跟#include一样,拷贝文件的内容。
2》可以自动防止文件的内容被重复拷贝。
不需要在头文件中加入下面的预处理指令:
#ifndef _STDIO_H_
#define _STDIO_H_
函数声明等操作
#endif
(5)NSLog和printf的区别
1》NSLog接收OC字符串作为参数,printf接受C语言字符串作为参数。
2》NSLog输出后会自动换行,printf输出后不会自动换行。
3》使用NSLog需要#import <Foundation/Foundation.h>,使用printf需要#include <stdio.h>。
(6)布尔型BOOL
BOOL的本质:typedef signed char BOOL;
BOOL变量的取值:YES/NO
#define YES (BOOL)1
#define NO (BOOL)0
由BOOL变量的取值可以看出,BOOL变量可以当做整数1、0来使用。
二、OC的面向对象
1. 面向对象思想
C是面向过程的,OC是面向对象的。
1》面向过程与面向对象的区别
面向过程关注的时解决问题需要哪些步骤;面向对象关注的时解决问题需要哪些对象。
2》术语
面向过程:Procedure Oriented
面向对象:Object Oriented,简称OO
面向对象编程:Object Oriented Programming ,简称OOP
2. 类和对象
(1)类的设计
1》类名
* 类名的第一个字母必须大写
* 不能有下划线
* 多个英文单词,用驼峰标识
* 一般名词都是类
2》属性
* 拥有相同属性和行为的对象都可以抽象出一个类
3》行为(功能)
* 谁最清楚这个行为,这个行为就应该在哪个类中,该交给谁执行这个行为,由该类决定
(2)类的声明
用来声明对象的属性和行为。
成员变量和方法不能用static等关键字修饰,不能跟C语言的函数或变量混淆。
</pre><pre name="code" class="objc">#import <Foundation/Foundation.h>
//: NSObject 目的是让Car这个类具备创建对象的能力
@interface Car : NSObject
{//大括号,用来声明对象属性
//成员变量(实例变量),默认初始化为0(成员变量不能在这里进行初始化操作)
//@public 可以让外部的指针间接访问对象内部的成员变量
@public
int wheels;
int speed;
}
//方法(行为)(方法也分声明和实现两步)
//方法名、参数、返回值
//只要是OC对象的方法,必须以减号- 开头
//OC方法中,任何数据类型都必须用小括号()括住
//OC方法中,小括号就一个作用:括住数据类型
- (void)run;
@end
</pre></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><h3><span style="font-family:SimHei;font-size:14px;font-weight: normal;">(3)类的实现</span></h3></div></blockquote><div><pre name="code" class="objc">//方法的实现(说清楚方法里面的功能)
@implementation Car
- (void)run
{
NSLog(@"车子跑起来了!");
}
@end
(4)创建对象
* 在使用类创建对象之前,系统会先将类加载到内存中;
* 在类中,成员变量是对象独有的,而方法是对象共有的。
//利用类来创建对象
//在OC中,想执行一些行为,就应该写上一个中括号[行为执行者 行为名称]
// [Car new];//执行了Car这个类的new行为来创建新对象
//定义一个指针变量p,p将来指向的是Car类型的对象
//[Car new]每次都会创建一个新的对象,并且会返回新对象本身(新对象的地址)
Car *p = [Car new];
//给p所指向的对象的属性赋值
p->wheels = 4;
p->speed = 120;
Car *p2 = [Car new];
p2->wheels = 5;
p2->speed = 210;
//给p所指向的对象发送一条run消息
[p run];
(5)对象与函数
1》对象成员变量作为函数参数:是值传递,传递到函数的只是对象成员变量的值。在函数里改变这个值并不会影响外界对象的值。
2》指向对象的指针作为函数参数:是地址传递,传递到函数的是指向对象的指针。如果在函数里对这个指针指向的对象的值进行了改变,外界的对象的值也将随之改变。
void test(int w, int s)
{
w = 20;
s = 200;
}
void test2(Car *newC)
{
newC->wheels = 5;
}
void test3(Car *newC)
{
Car *c2 = [Car new];
c2->wheels = 5;
c2->speed = 300;
newC = c2;//指针指向变了
newC->wheels = 6;
}
int main()
{
Car *c = [Car new];
c->wheels = 4;
c->speed = 120;
test(c->wheels, c->speed); // 值传递
test2(c); // 地址传递
test3(c); // 地址传递
return 0;
}
(6)匿名对象
//不要写类似匿名对象这样的代码,会造成内存泄露
[Car new]->speed = 300;
[[Car new] run];//每次[Car new]都会创建新对象。。
3. 方法
(1)OC方法与函数
方法:
1》对象方法都是以减号- 开头
2》对象方法的声明必须写在@interface和@end之间,对象方法的实现必须写在@implementation和@end之间
3》对象方法只能由对象来调用
4》对象方法归类和对象所有
函数:
1》函数能写在文件的任意位置(@interface和@end除外),函数归文件所有
2》函数调用不依赖于对象
3》函数内部不能直接通过成员变量名访问某个成员变量
(2)OC方法的使用注意
* 方法只有声明,没有实现(程序崩溃:闪退(运行过程中出错) 运行错误:unrecognized selector sent to instance 0x7fdcab409690)
* 方法没有声明,只有实现(编译器警告,但是能调用,这是OC的弱语法)
* OC在运行过程中才会检测有没有相应的方法。
* 编译的时候:如果访问了不存在的成员变量则直接报错;如果访问了不存在的方法,仅仅只是警告。
* 冒号也是方法名的一部分。
* 同一个类中不允许有两个对象方法同名。
#import <Foundation/Foundation.h>
@interface JiSuanQi : NSObject
//方法名:pi
- (double)pi;
//OC方法中,一个参数对应一个冒号
//方法名:pingFang:(冒号也是方法名的一部分)
- (int)pingFang:(int)num;
//- (int)sum:(int)num1 :(int)num2;
//方法名:sumWithNum1:andNum2:
- (int)sumWithNum1:(int)num1 andNum2:(int)num2;
//- (int)sumWithNum1:(int)num1 andNum2:(int)num2 andNum3:(int)num3;
@end
@implementation JiSuanQi
- (double)pi
{
return 3.14;
}
- (int)pingFang:(int)num
{
return num*num;
}
//- (int)sum:(int)num1 :(int)num2
- (int)sumWithNum1:(int)num1 andNum2:(int)num2
{
return num1+num2;
}
@end
(3)方法的分类
类方法和对象方法可以同名。
1》类方法
格式:[类名 方法名];
* 以加号+ 开头;
* 只能用类名调用,对象不能调用;
* 类方法中不能访问实例变量(成员变量);
好处:不依赖于对象,执行效率高。
使用场合:当方法内部不需要使用到成员变量时,就可以改为类方法。
2》对象方法
格式:[对象名 方法名];
* 以减号- 开头;
* 只能让对象调用,没有对象,这个方法就不可能被执行;
* 对象方法能访问实例变量(成员变量)。
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
int age;
}
+ (void)printClassName;
- (void)test;
+ (void)test;
@end
@implementation Person
+ (void)printClassName
{
//实例变量age不能再类方法中访问
//NSLog(@"this class call Person = %d", age);
NSLog(@"this class call Person");
}
- (void)test
{
NSLog(@"test对象方法");
[Person test];
}
+ (void)test
{
NSLog(@"test类方法");
//死循环
//[Person test];
}
@end
int main()
{
//用对象调用类方法,运行报错,不能识别。。
Person *p = [Person new];
[p test];
[Person test];
[Person printClassName];
return 0;
}
(4)setter方法和getter方法
一般为了防止使用@public对对象的成员随意赋值,我们使用setter方法和getter方法来管理成员的访问。
1》setter方法
* 作用:给外界提供一个方法用来设置成员变量,可以在方法里面过滤掉一些不合理的值
* 命名规范:
方法都是以set开头,而且后面跟上成员变量名,成员变量名的首字母必须大写;
返回值一定是void,一定要接受一个参数,而且参数类型跟成员变量类型一致;
形参名称不要跟成员变量同名。
2》getter方法
* 作用:返回对象内部的成员变量
* 命名规范:
肯定有返回值,而且类型跟成员变量一致;
不需要接收任何参数;
getter方法的名称一般就跟成员变量同名。
3》成员变量的命名规范
* 成员变量都以下划线_ 开头;
* 可以跟get方法的名称区分开;
* 可以跟其他局部变量区分开,一看到下划线开头的变量,一般都是成员变量。
4. self关键字
当成员变量和局部变量同名时,系统就会采取就近原则,访问局部变量,而不是访问成员变量。这时,我们可以用self访问成员变量,区分同名的局部变量。
概念:谁调用了当前方法,self就代表谁(方法调用者)
* self出现在对象方法中,self代表对象
* self出现在类方法中,self代表类
格式:
1》self->成员变量名:访问当前方法调用的成员变量
2》[self 方法名]:调用方法(对象方法或类方法)
使用场合:所有的OC方法中,包括对象方法和类方法,不能出现在函数中。
-(void)test
{
// self死循环【注意】
//self是个指针,指向方法调用者,代表当前对象
[self test];
}
三、OC面向对象的三大特征
1. 封装
2. 继承* readonly:只读,只提供getter方法就行。
* 成员变量:一定要以下划线_ 开头
作用:让成员变量与get方法名区分开;可以跟局部变量区分开。
成员变量尽量不要用@public,以便更好地实现封装。
封装的好处:
1》更加接近人类的思考方式,只需要关注对象和行为,不需要关注具体实现步骤。
2》过滤不合理的值,屏蔽内部的处理过程,让外界不需要关注内容的细节。
* 直接调用父类中的某个方法。
* super处在对象方法中,那么就会调用父类的对象方法;super处在类方法中,那么就会调用父类的类方法。
* 使用场合:子类重写父类的方法时,想保留父类的某些做法。
* 将具有相同属性和行为的类,抽取出一个父类;
* 子类在父类的基础上,再扩充属性和方法;
* 子类的方法和属性的访问过程:先去子类里面找,如果子类没有,再去父类里面找;
* 父类被继承了,但是还是可以照常使用这个类;
* 全部OC类的最终父类是NSObject。
专业术语:父类/超类 superclass、子类 subclass/subclasses
(1)继承的好处和坏处
好处:不改变原来模型的基础上,扩充方法;建立了类与类之间的联系;抽取了公共的代码,减少代码编写;子类可以拥有父类的所有成员变量和方法。
坏处:耦合性强,类之间的关系太紧密(改一类而动很多类)。
(2)继承的使用场合
* 当两个类拥有相同的属性和方法的时候,就可以将相同的东西抽取到一个父类中;
* 当A类完全拥有B类中部分属性和方法时,可以考虑让B类继承A类,或考虑B类组合A类。
(3)继承的注意事项
* 继承是单继承,不能继承自多个类;
* 父类必须声明在子类前面;
* 子类和父类不能有相同的成员变量;
* 子类可以重写父类的方法,调用某个对象的方法时,优先区当前对象的类中寻找,之后才会往父类方向找。
(4)super
格式:[super 方法名];
super的作用:
(5)继承和组合
继承:xxx 是 xx
组合:xxx 拥有 xx
#import <Foundation/Foundation.h>
/*************Animal声明****************/
@interface Animal : NSObject
{
int _age;
double _weight;
}
- (void)setAge:(int)age;
- (int)age;
- (void)setWeight:(double)weight;
- (double)weight;
@end
/*************Animal实现****************/
@implementation Animal
- (void)setAge:(int)age
{
_age = age;
}
- (int)age
{
return _age;
}
- (void)setWeight:(double)weight
{
_weight = weight;
}
- (double)weight
{
return _weight;
}
@end
/*************Dog声明****************/
//: Animal 代表继承了Animal,相当于拥有了Animal里面的所有成员变量和方法
//Animal称为Dog的父类
//Dog称为Animal的子类
@interface Dog : Animal
@end
/*************Dog实现****************/
@implementation Dog
@end
/*************Cat声明****************/
@interface Cat : Animal
@end
/*************Cat实现****************/
@implementation Cat
@end
3. 多态
概念:某一类事物的多种形态。
(1)多态的实现
* 没有继承就没有多态。
* 子类对象赋值给父类的指针,然后用父类指针就可以访问子类对象的属性和方法了。
* 多态是动态绑定,即在运行时,根据对象的具体类型来确定动态调用的方法是哪个子类(或父类本身)的方法。
(2)多态的好处和坏处
好处:如果函数、方法参数中使用的时父类类型的,可以传入父类、子类对象。
坏处:不能访问子类的属性(成员变量),不能调用子类特有的方法(子类有父类没有的方法)(除非强制类型转换)
#import <Foundation/Foundation.h>
//Animal
@interface Animal : NSObject
- (void)eat;
@end
@implementation Animal
- (void)eat
{
NSLog(@"Animal eating..");
}
@end
//Dog
@interface Dog : Animal
- (void)run;
@end
@implementation Dog
- (void)eat
{
NSLog(@"Dog eating..");
}
- (void)run
{
NSLog(@"Dog running");
}
@end
//Cat
@interface Cat : Animal
@end
@implementation Cat
- (void)eat
{
NSLog(@"Cat eating..");
}
@end
//如果形参中使用的时父类类型,可以传入父类对象、子类对象
void feed(Animal *a)
{
[a eat];
}
int main()
{
/*
//多种形态
Dog *d = [Dog new]; //Dog类型
//多态:父类指针指向子类
Animal *a = [Dog new];
[a eat]; //调用方法时 会检测对象的真实形象
// 只是警告,弱语法
// Cat *c = [Animal new];
// NSSring *s = [Cat new];
*/
Dog *d = [Dog new];
feed(d);
Cat *c = [Cat new];
feed(c);
//多态的局限性:父类类型的指针变量,不能用来调用子类的方法 [aa run];
//虽然只是警告(编译器),运行时动态检测(所以运行通过)
Animal *aa = [Dog new];
//[aa run]; // 错误
Dog *dd = (Dog *)aa; //强制转换就好了,(Dog *)类型转换是给编译器看的
[dd run]; // 正确
return 0;
}