黑马程序员-OC里的三大特性
2014-12-24 21:50
225 查看
[align=center]------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------[/align]
三大特性,封装,继承,多态
多态的两种形式–重载与重写。
set方法
1.作用:提供一个方法给外界设置成员变量值,可以在方法里面对参数进行相应过滤
2.命名规范:
1>方法名必须以set开头
2>set后面跟上成员变量的中称,成员变量的首字母必须大写
3>返回值一定是void
4>一定要接收一个参数,而且参数类型跟成员变量类型一致
5>形参的名称不能跟成员变量名一样
- (void)setAge:(int)newAge;
get方法
1.作用:返回对象内部的成员变量
2.命名规范:
1>肯定有返回值,返回值类型肯定与成员变量类型一致
2>方法名跟成员变量名一样(java的get方法必须以get开头)
- (int)age;
成员变量的命名规范:一定要以下划线_开头
作用:
1.让成员变量和get方法的名称区分开
2.可以跟局部变量区分开,一看到下划线开头的变量,一般都是成员变量。
通信失败
[Person test]:unrecognized selector sent to instance
给Person对象发送了一个不能识别的消息
oc是在运行过程中才会检测对象有没有实现相应的方法
对象方法
1.以减号-开头
2.只能由对象来调用
类方法
1.以加号+开头
2.只能由类(名)来调用
3.类方法中不能方问成员变量(实例)
类方法的好处和使用场合
1.不依赖于对象,执行效率高
2.能用类方法尽量用类名
3.场合:当方法内部不需要使用到成员变量时,就可以改为类方法
可以类方法和对象方法同名
实例变量age不能在类方法进行方问。
类方法调用 这样只会找类方法来用
[Person printClassName];
对象方法调用 这样只会找对象方法来用
Person *p = [Person new];
这么调用会抛出警报
[p printClassName];
当局部对象名称与成员变量重名。
//使用时报:local declaration of '_age' hides instance variable
self关键字 关于类方法与对象方法
self的用途
1.谁调用了当前方法,self就代表谁
self出现在对象方法中,self就代表对象
self出现在类方法中,self就代表类
2.在对象方法利用"self->成员变量名"访问当前对象内部的成员变量
3.[self 方法名]可以调用其他对象方法\类方法
继承的好处:
1.抽取重复代码
2.建立了类之间的关系
3.子类可以拥有父类中的所有成员变量和方法
注意点
1.基本上所有类的根类是NSObject
注意事项
1.重写:子类重新实现父类中的某个方法,覆盖父类以前的做法
2.父类必须声明在子类的前面。
3.子类不能拥有和父类相同的成员变量
4.调用某个对象方法时,优先去当前对象中寻找,如果找不到去父类中寻找。
坏处:耦合性太强
继承的使用场合。
1.当两个类拥有相同属性和方法的时候,就可以将相同的东西抽取到一个父类中
2.当a类完全拥有b类中的部分属性和方法时,可以考虑让b类继承a类
a
{
int _age;
int _no;
}
b : a
{
int _weight;
}
//继承 :xx是xxx
//组合 :xxx拥有xxx
组合
A
{
int _age;
int _no
}
B
{
A *a;
int _weight;
}
super的作用
1.直接调用父类中的某一个方法
2.super处在对象方法中,那么就会调用父类的对象方法。
3.super处在类方法中,那么就会调用父类的类方法。
使用场景
子类重写父类的方法时,想保留父类的一些行为。
多态
1.没有继承就没有多态
2.代码的体现:父类类型的指针指向子类对象
3
多态的好处
用一个父类指针变量就可以指向多个子类对象
多态的局限
父类类型的变量不能用来调用子类特有的方法(子类有,父类没有的方法),必须强转为子类类型变量后,才能直接调用子类特有的方法。
解决办法,强制转换
Dog *d = (Dog *)a;
多态的灵活使用
如果参数中使用的是父类类型,可以传入父类,子类对象,调用方法时会检测对象的真实形象。
多态:父类指针指向子类对象
NSObject *n = [Animal new];
封装第一个例子 set get
/*
类名:学生 student
属性:年龄 age
行为:学习 study
*/
当属性没有@public 将无法直接通过对象来修改属性
但是可以通过对象方法来修改属性。
一般能通过方法给外界设置属性值的方法为set方法
一般能通过方法让外界获取属性值的主法为get方法
bogon:04oc whome$ touch oc13.m
bogon:04oc whome$ open oc13.m
bogon:04oc whome$ cc oc13.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-09-16 23:52:25.987 a.out[561:507] 1岁的学生在学习
2014-09-16 23:52:25.992 a.out[561:507] 10岁的学生在学习
2014-09-16 23:52:25.993 a.out[561:507] 学生的年龄是10岁
封装第二个例子 成员变量的命名规范。
bogon:~ whome$ cd Desktop/oc/04oc/
bogon:04oc whome$ open oc14.m
bogon:04oc whome$ cc oc14.m -framework Foundation
bogon:04oc whome$ ./a.out
封装第三个例子 设计一个成oc15.m
bogon:04oc whome$ touch oc15.m
bogon:04oc whome$ open oc15.m
bogon:04oc whome$ cc oc15.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-09-23 07:00:32.628 a.out[997:507] 总分:190,平均分:95
bogon:04oc whome$
封装第四个例子弱语法
弱语法就是只警告不报错的语法
类 person
调用一个不存在的方法test收集调试信息并理解
//闪退
bogon:04oc whome$ cc oc16.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-09-23 07:59:04.282 a.out[1104:507] 哈哈哈
oc17.m:13:8: warning: 'Person' may not respond to 'test'
[p test];
~ ^
1 warning generated.
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_NSObject", referenced from:
_OBJC_CLASS_$_Person in oc17-6479b2.o
"_OBJC_METACLASS_$_NSObject", referenced from:
_OBJC_METACLASS_$_Person in oc17-6479b2.o
"__objc_empty_cache", referenced from:
_OBJC_METACLASS_$_Person in oc17-6479b2.o
_OBJC_CLASS_$_Person in oc17-6479b2.o
"_objc_msgSend", referenced from:
_main in oc17-6479b2.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
bogon:04oc whome$ cc oc17.m -framework Foundation
oc17.m:13:8: warning: 'Person' may not respond to 'test'
[p test];
~ ^
1 warning generated.
bogon:04oc whome$ ./a.out
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person test]: unrecognized selector sent to instance 0x7fbaab502640'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff8e5db25c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff8bffbe75 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8e5de12d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x00007fff8e539272 ___forwarding___ + 1010
4 CoreFoundation 0x00007fff8e538df8 _CF_forwarding_prep_0 + 120
5 a.out 0x0000000102772f64 main + 68
6 libdyld.dylib 0x00007fff939ec5fd start + 1
7 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Abort trap: 6
错误总结
[Person test]:unrecognized selector sent to instance
给Person对象发送了一个不能识别的消息
terminate called throwing an exception
程序被终止了
封装第五个例子类方法
类 person
类行为,类方法和对象方法比较
//类方法 比对象方法效率高
bogon:04oc whome$ cc oc17.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 07:26:55.549 a.out[653:507] 这个类叫做Person
2014-10-06 07:26:55.552 a.out[653:507] 调用了test类方法
2014-10-06 07:26:55.553 a.out[653:507] 调用了test对象方法 0
封装第六个例子类方法练习
类计算器
类行为 求和,求平均值
bogon:04oc whome$ touch oc18.m
bogon:04oc whome$ open oc18.m
bogon:04oc whome$ cc oc18.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 07:45:54.458 a.out[684:507] a=11
类方法注意事项,类方法不能自己调用自己,会进入死循环。
封装第七个例子self关键字 关于成员变量
bogon:04oc whome$ touch oc19.m
bogon:04oc whome$ open oc19.m
bogon:04oc whome$ cc oc19.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 21:42:00.426 a.out[467:507] age:10
2014-10-06 21:42:00.430 a.out[467:507] self->age:10
封装第八个例子self关键字 关于类方法与对象方法
类 狗dog
类行为 叫和跑 bark,run
bogon:04oc whome$ touch oc20.m
bogon:04oc whome$ open oc20.m
//self关键字 关于类方法与对象方法
/*
self的用途
1.谁调用了当前方法,self就代表谁
self出现在对象方法中,self就代表对象
self出现在类方法中,self就代表类
2.在对象方法利用"self->成员变量名"访问当前对象内部的成员变量
3.[self 方法名]可以调用其他对象方法\类方法
*/
bogon:04oc whome$ cc oc20.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 22:34:25.917 a.out[530:507] 对象方法 汪汪汪
2014-10-06 22:34:25.922 a.out[530:507] 对象方法 跑起来了
2014-10-06 22:34:25.922 a.out[530:507] 类方法 汪汪汪
2014-10-06 22:34:25.923 a.out[530:507] 类方法 跑起来了
封装第九个例子self关键字 注意事项
类 Person 人
bogon:04oc whome$ touch oc21.m
bogon:04oc whome$ open oc21.m
//self的注意事项
/*
self的用途
1.谁调用了当前方法,self就代表谁
self出现在对象方法中,self就代表对象
self出现在类方法中,self就代表类
2.在对象方法利用"self->成员变量名"访问当前对象内部的成员变量
3.[self 方法名]可以调用其他对象方法\类方法
*/
bogon:04oc whome$ cc oc21.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 23:48:10.305 a.out[584:507] 调用了-test方法
2014-10-06 23:48:10.308 a.out[584:507] 调用了+test方法
2014-10-06 23:48:10.308 a.out[584:507] 调用了-test方法
2014-10-06 23:48:10.309 a.out[584:507] 调用了+test方法
2014-10-06 23:48:10.310 a.out[584:507] 调用了-haha1方法
2014-10-06 23:48:10.311 a.out[584:507] 调用了-haha1方法
2014-10-06 23:48od0.315 a.out[584:507] 调用了-haha1方法
封装第十个例子 继承
类b继承类a
基类 动物类
猫,狗类 继承动物类
bogon:04oc whome$ touch oc22.m
bogon:04oc whome$ open oc22.m
//继承
/*
继承的好处:
1.抽取重复代码
2.建立了类之间的关系
3.子类可以拥有父类中的所有成员变量和方法
注意点
1.基本上所有类的根类是NSObject
*/
//: Animal 继承了Animal,相当于拥有了Animal里面的所有成员变量和方法
// Animal称为Dog的父类
// Dog称为Animal的子类
bogon:04oc whome$ cc oc22.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-07 00:41:54.872 a.out[648:507] dog age=10
2014-10-07 00:41:54.875 a.out[648:507] cat age=10
封装第十一个例子 继承的使用注意
查看NSObject.h
xcode右键->contents-developer-platforms-iphoneOS platform-developer-sdk-iphoneos6.0sdk-system-library-frameworks-Foundation.framework-Headers-NSObject.h
bogon:04oc whome$ touch oc23.m
bogon:04oc whome$ open oc23.m
//继承的使用注意
#import <Foundation/Foundation.h>
/*
注意事项
1.重写:子类重新实现父类中的某个方法,覆盖父类以前的做法
2.父类必须声明在子类的前面。
3.子类不能拥有和父类相同的成员变量
4.调用某个对象方法时,优先去当前对象中寻找,如果找不到去父类中寻找。
坏处:耦合性太强
*/
bogon:04oc whome$ cc oc23.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-07 01:22:18.238 a.out[702:507] Person run
2014-10-07 01:22:18.242 a.out[702:507] Person +test
2014-10-07 01:22:18.243 a.out[702:507] Student +test
2014-10-07 01:22:18.244 a.out[702:507] Student +test
封装第十二个例子 继承的使用场合
bogon:04oc whome$ touch oc24.m
bogon:04oc whome$ open oc24.m
#import<Foundation/Foundation.h>
/*
继承的使用场合。
1.当两个类拥有相同属性和方法的时候,就可以将相同的东西抽取到一个父类中
2.当a类完全拥有b类中的部分属性和方法时,可以考虑让b类继承a类
a
{
int _age;
int _no;
}
b : a
{
int _weight;
}
//继承 :xx是xxx
//组合 :xxx拥有xxx
组合
A
{
int _age;
int _no
}
B
{
A *a;
int _weight;
}
*/
bogon:04oc whome$ cc oc24.m -framework Foundation
封装第十三个例子 继承 super关键字
bogon:04oc whome$ touch oc25.m
bogon:04oc whome$ open oc25.m
//继承 super关键字
#import <Foundation/Foundation.h>
/*
僵尸
跳跃僵尸,舞王僵尸,铁桶僵尸
*/
/*
super的作用
1.直接调用父类中的某一个方法
2.super处在对象方法中,那么就会调用父类的对象方法。
3.super处在类方法中,那么就会调用父类的类方法。
使用场景
子类重写父类的方法时,想保留父类的一些行为。
*/
bogon:04oc whome$ cc oc25.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-07 02:50:50.673 a.out[831:507] 往前跳两下
2014-10-07 02:50:50.677 a.out[831:507] 往前挪两步
2014-10-07 02:50:50.678 a.out[831:507] xoombie -test
2014-10-07 02:50:50.689 a.out[831:507] zoombie +test
封装第十四个例子 多态
多态,多种形态
bogon:04oc whome$ touch oc26.m
bogon:04oc whome$ open oc26.m
/*
多态
1.没有继承就没有多态
2.代码的体现:父类类型的指针指向子类对象
3
多态的好处
用一个父类指针变量就可以指向多个子类对象
多态的局限
父类类型的变量不能用来调用子类特有的方法(子类有,父类没有的方法),必须强转为子类类型变量后,才能直接调用子类特有的方法。
解决办法,强制转换
Dog *d = (Dog *)a;
*/
//多态的灵活使用
//如果参数中使用的是父类类型,可以传入父类,子类对象,调用方法时会检测对象的真实形象。
void feed(Animal *aa)
{
[aa eat];
}
bogon:04oc whome$ cc oc26.m -framework Foundation
oc26.m:65:10: warning: incompatible pointer types initializing 'Cat *' with an
expression of type 'Animal *' [-Wincompatible-pointer-types]
Cat *c = [Animal new];//oc是弱语法,只有警告
^ ~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/objc/NSObject.h:59:1: note:
class method 'new' is assumed to return an instance of its receiver type
('Animal *')
+ (id)new;
^
oc26.m:66:10: warning: incompatible pointer types initializing 'Dog *' with an
expression of type 'Cat *' [-Wincompatible-pointer-types]
Dog *dd = [Cat new];
^ ~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/objc/NSObject.h:59:1: note:
class method 'new' is assumed to return an instance of its receiver type
('Cat *')
+ (id)new;
^
oc26.m:68:15: warning: incompatible pointer types initializing 'NSString *' with
an expression of type 'Cat *' [-Wincompatible-pointer-types]
NSString *s = [Cat new];//oc是弱语法,只有警告
^ ~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/objc/NSObject.h:59:1: note:
class method 'new' is assumed to return an instance of its receiver type
('Cat *')
+ (id)new;
^
oc26.m:75:10: warning: incompatible pointer types passing 'NSObject *' to
parameter of type 'Animal *' [-Wincompatible-pointer-types]
feed(n);
^
oc26.m:49:19: note: passing argument to parameter 'aa' here
void feed(Animal *aa)
^
oc26.m:76:10: warning: incompatible pointer types passing 'NSObject *' to
parameter of type 'Animal *' [-Wincompatible-pointer-types]
feed(an);
^~
oc26.m:49:19: note: passing argument to parameter 'aa' here
void feed(Animal *aa)
^
oc26.m:81:8: warning: 'Animal' may not respond to 'run'
[a run];
~ ^
6 warnings generated.
bogon:04oc whome$ ./a.out
2014-10-07 03:57:59.265 a.out[940:507] dog eat
2014-10-07 03:57:59.267 a.out[940:507] dog eat
2014-10-07 03:57:59.267 a.out[940:507] eat
2014-10-07 03:57:59.268 a.out[940:507] dog eat
2014-10-07 03:57:59.268 a.out[940:507] dog eat
2014-10-07 03:57:59.269 a.out[940:507] eat
2014-10-07 03:57:59.269 a.out[940:507] cat eat
2014-10-07 03:57:59.270 a.out[940:507] dog run
2014-10-07 03:57:59.270 a.out[940:507] dog run
[align=center]------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------[/align]
三大特性,封装,继承,多态
多态的两种形式–重载与重写。
set方法
1.作用:提供一个方法给外界设置成员变量值,可以在方法里面对参数进行相应过滤
2.命名规范:
1>方法名必须以set开头
2>set后面跟上成员变量的中称,成员变量的首字母必须大写
3>返回值一定是void
4>一定要接收一个参数,而且参数类型跟成员变量类型一致
5>形参的名称不能跟成员变量名一样
- (void)setAge:(int)newAge;
get方法
1.作用:返回对象内部的成员变量
2.命名规范:
1>肯定有返回值,返回值类型肯定与成员变量类型一致
2>方法名跟成员变量名一样(java的get方法必须以get开头)
- (int)age;
成员变量的命名规范:一定要以下划线_开头
作用:
1.让成员变量和get方法的名称区分开
2.可以跟局部变量区分开,一看到下划线开头的变量,一般都是成员变量。
通信失败
[Person test]:unrecognized selector sent to instance
给Person对象发送了一个不能识别的消息
oc是在运行过程中才会检测对象有没有实现相应的方法
对象方法
1.以减号-开头
2.只能由对象来调用
类方法
1.以加号+开头
2.只能由类(名)来调用
3.类方法中不能方问成员变量(实例)
类方法的好处和使用场合
1.不依赖于对象,执行效率高
2.能用类方法尽量用类名
3.场合:当方法内部不需要使用到成员变量时,就可以改为类方法
可以类方法和对象方法同名
实例变量age不能在类方法进行方问。
类方法调用 这样只会找类方法来用
[Person printClassName];
对象方法调用 这样只会找对象方法来用
Person *p = [Person new];
这么调用会抛出警报
[p printClassName];
当局部对象名称与成员变量重名。
//使用时报:local declaration of '_age' hides instance variable
self关键字 关于类方法与对象方法
self的用途
1.谁调用了当前方法,self就代表谁
self出现在对象方法中,self就代表对象
self出现在类方法中,self就代表类
2.在对象方法利用"self->成员变量名"访问当前对象内部的成员变量
3.[self 方法名]可以调用其他对象方法\类方法
继承的好处:
1.抽取重复代码
2.建立了类之间的关系
3.子类可以拥有父类中的所有成员变量和方法
注意点
1.基本上所有类的根类是NSObject
注意事项
1.重写:子类重新实现父类中的某个方法,覆盖父类以前的做法
2.父类必须声明在子类的前面。
3.子类不能拥有和父类相同的成员变量
4.调用某个对象方法时,优先去当前对象中寻找,如果找不到去父类中寻找。
坏处:耦合性太强
继承的使用场合。
1.当两个类拥有相同属性和方法的时候,就可以将相同的东西抽取到一个父类中
2.当a类完全拥有b类中的部分属性和方法时,可以考虑让b类继承a类
a
{
int _age;
int _no;
}
b : a
{
int _weight;
}
//继承 :xx是xxx
//组合 :xxx拥有xxx
组合
A
{
int _age;
int _no
}
B
{
A *a;
int _weight;
}
super的作用
1.直接调用父类中的某一个方法
2.super处在对象方法中,那么就会调用父类的对象方法。
3.super处在类方法中,那么就会调用父类的类方法。
使用场景
子类重写父类的方法时,想保留父类的一些行为。
多态
1.没有继承就没有多态
2.代码的体现:父类类型的指针指向子类对象
3
多态的好处
用一个父类指针变量就可以指向多个子类对象
多态的局限
父类类型的变量不能用来调用子类特有的方法(子类有,父类没有的方法),必须强转为子类类型变量后,才能直接调用子类特有的方法。
解决办法,强制转换
Dog *d = (Dog *)a;
多态的灵活使用
如果参数中使用的是父类类型,可以传入父类,子类对象,调用方法时会检测对象的真实形象。
多态:父类指针指向子类对象
NSObject *n = [Animal new];
封装第一个例子 set get
/*
类名:学生 student
属性:年龄 age
行为:学习 study
*/
当属性没有@public 将无法直接通过对象来修改属性
但是可以通过对象方法来修改属性。
一般能通过方法给外界设置属性值的方法为set方法
一般能通过方法让外界获取属性值的主法为get方法
bogon:04oc whome$ touch oc13.m
bogon:04oc whome$ open oc13.m
#import<Foundation/Foundation.h> /* 类名:学生 student 属性:年龄 age 行为:学习 study */ @interface Student : NSObject { //成员变量尽量不要用@public int age; } /* set方法 1.作用:提供一个方法给外界设置成员变量值,可以在方法里面对参数进行相应过滤 2.命名规范: 1>方法名必须以set开头 2>set后面跟上成员变量的中称,成员变量的首字母必须大写 3>返回值一定是void 4>一定要接收一个参数,而且参数类型跟成员变量类型一致 5>形参的名称不能跟成员变量名一样 */ - (void)setAge:(int)newAge; /* get方法 1.作用:返回对象内部的成员变量 2.命名规范: 1>肯定有返回值,返回值类型肯定与成员变量类型一致 2》方法名跟成员变量名一样(java的get方法必须以get开头) */ - (int)age; - (void)study; @end
@implementation Student //set方法的实现 - (void)setAge:(int)newAge { //对传进来的参数进行过滤 if(newAge<=0) { newAge = 1; } age = newAge; } //get方法的实现 - (int)age { return age; } - (void)study { NSLog(@"%d岁的学生在学习",age); } @end
int main() { Student *stu = [Student new]; //不建议使用下面这种方法直接改属性值。 //stu->age = 10; //因为像下面这种不规范的赋值是无法在类接收属性值时控制的 //stu->age = -10 //推荐下面这种封装方法 [stu setAge:0]; [stu study]; [stu setAge:10]; [stu study]; //get方法 int age = [stu age]; NSLog(@"学生的年龄是%d岁",age); return 0; }
bogon:04oc whome$ cc oc13.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-09-16 23:52:25.987 a.out[561:507] 1岁的学生在学习
2014-09-16 23:52:25.992 a.out[561:507] 10岁的学生在学习
2014-09-16 23:52:25.993 a.out[561:507] 学生的年龄是10岁
封装第二个例子 成员变量的命名规范。
bogon:~ whome$ cd Desktop/oc/04oc/
bogon:04oc whome$ open oc14.m
#import <Foundation/Foundation.h> /* 枚举对象 */ typedef enum{ SexMan, SexWoman }Sex; /* 类名:学生 Student 属性:学号,年龄 no,age */ @interface Student : NSObject { /* 成员变量的命名规范:一定要以下划线_开头 作用: 1.让成员变量和get方法的名称区分开 2.可以跟局部变量区分开,一看到下划线开头的变量,一般都是成员变量。 */ int _no; Sex _sex; } // sex的set和get方法 - (void)setSex:(Sex)sex; - (Sex)sex; // no的set和get方法 - (void)setNo:(int)no; - (int)no; @end
//类的实现 @implementation Student - (void)setSex:(Sex)sex { _sex = sex; } - (Sex)sex { return _sex; } - (void)setNo:(int)no { _no = no; } - (int)no { return _no; } @end
int main() { Student *stu = [Student new]; [stu setSex:SexMan]; [stu setNo:10]; [stu sex]; [stu no]; }
bogon:04oc whome$ cc oc14.m -framework Foundation
bogon:04oc whome$ ./a.out
封装第三个例子 设计一个成oc15.m
bogon:04oc whome$ touch oc15.m
bogon:04oc whome$ open oc15.m
#import <Foundation/Foundation.h> /* 设计一个成绩类 属性: c语言成绩(可读可写) oc成绩(可读可写) 总分 (只读) 平均分 (只读) 行为: 比较c语言成绩:跟另外一个成绩对象比较c语言成绩,返回成绩差(自己-其他成绩) 比较oc成绩:跟另外一个成绩对象比较oc语言成绩,返回成绩差(自己 - 其他成绩) 比较ios成绩:跟另外一个成绩对象比较ios语言成绩,返回成绩差(自己-其他成绩) 计算总分:算出3科成绩的总分 计算平均分:算出3科成绩的平均分 */ @interface Score : NSObject { int _cScore; //c语言成绩 int _ocScore;//oc成绩 int _totalScore;//总分 int _averageScore;//平均分 } - (void)setCScore:(int)cScore; - (int)cScore; - (void)setOcScore:(int)ocScore; - (int)ocScore; - (int)totalScore; - (int)averageScore; @end
@implementation Score - (void)setCScore:(int)cScore { _cScore = cScore; //计算总分 _totalScore = _cScore + _ocScore; _averageScore = _totalScore/2; } - (int)cScore { return _cScore; } - (void)setOcScore:(int)ocScore { _ocScore = ocScore; //计算总分 _totalScore = _cScore + _ocScore; _averageScore = _totalScore/2; } //监听成员变量的改变 - (int)ocScore { return _ocScore; } - (int)totalScore { return _totalScore; } - (int)averageScore { return _averageScore; } @end
int main(){ Score *s = [Score new]; [s setCScore:90]; [s setOcScore:100]; int t = [s totalScore]; int a = [s averageScore]; NSLog(@"总分:%d,平均分:%d",t,a); return 0; }
bogon:04oc whome$ cc oc15.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-09-23 07:00:32.628 a.out[997:507] 总分:190,平均分:95
bogon:04oc whome$
封装第四个例子弱语法
弱语法就是只警告不报错的语法
类 person
调用一个不存在的方法test收集调试信息并理解
#import <Foundation/Foundation.h> @interface Person : NSObject - (void)test; @end @implementation Person //如果没有实现就会报错,如果是没有声明,有实现的话,就只报个警报 - (void)test { NSLog(@"哈哈哈"); } @end
//闪退
/* [Person test]:unrecognized selector sent to instance 给Person对象发送了一个不能识别的消息 terminate called throwing an exception 程序被终止了 */ int main() { Person *p = [Person new]; //oc是在运行过程中才会检测对象有没有实现相应的方法 [p test]; return 0; }
bogon:04oc whome$ cc oc16.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-09-23 07:59:04.282 a.out[1104:507] 哈哈哈
oc17.m:13:8: warning: 'Person' may not respond to 'test'
[p test];
~ ^
1 warning generated.
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_NSObject", referenced from:
_OBJC_CLASS_$_Person in oc17-6479b2.o
"_OBJC_METACLASS_$_NSObject", referenced from:
_OBJC_METACLASS_$_Person in oc17-6479b2.o
"__objc_empty_cache", referenced from:
_OBJC_METACLASS_$_Person in oc17-6479b2.o
_OBJC_CLASS_$_Person in oc17-6479b2.o
"_objc_msgSend", referenced from:
_main in oc17-6479b2.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
bogon:04oc whome$ cc oc17.m -framework Foundation
oc17.m:13:8: warning: 'Person' may not respond to 'test'
[p test];
~ ^
1 warning generated.
bogon:04oc whome$ ./a.out
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person test]: unrecognized selector sent to instance 0x7fbaab502640'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff8e5db25c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff8bffbe75 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8e5de12d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x00007fff8e539272 ___forwarding___ + 1010
4 CoreFoundation 0x00007fff8e538df8 _CF_forwarding_prep_0 + 120
5 a.out 0x0000000102772f64 main + 68
6 libdyld.dylib 0x00007fff939ec5fd start + 1
7 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Abort trap: 6
错误总结
[Person test]:unrecognized selector sent to instance
给Person对象发送了一个不能识别的消息
terminate called throwing an exception
程序被终止了
封装第五个例子类方法
类 person
类行为,类方法和对象方法比较
//类方法 比对象方法效率高
#import <Foundation/Foundation.h> /* 对象方法 1.以减号-开头 2.只能由对象来调用 类方法 1.以加号+开头 2.只能由类(名)来调用 3.类方法中不能方问成员变量(实例) 类方法的好处和使用场合 1.不依赖于对象,执行效率高 2.能用类方法尽量用类名 3.场合:当方法内部不需要使用到成员变量时,就可以改为类方法 可以类方法和对象方法同名 */ @interface Person : NSObject { int age; } + (void)printClassName; - (void)test; + (void)test; @end
@implementation Person + (void)printClassName { //error instance variable 'age' accessed in class method //实例变量age不能在类方法进行方问。 // NSLog(@"这个类叫做Person %d",age); NSLog(@"这个类叫做Person"); } - (void)test { NSLog(@"调用了test对象方法 %d",age); } + (void)test { NSLog(@"调用了test类方法"); } @end
int main() { //类方法调用 这样只会找类方法来用 [Person printClassName]; //对象方法调用 这样只会找对象方法来用 Person *p = [Person new]; //这么调用会抛出警报 //[p printClassName]; s [Person test]; [p test]; return 0; }
bogon:04oc whome$ cc oc17.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 07:26:55.549 a.out[653:507] 这个类叫做Person
2014-10-06 07:26:55.552 a.out[653:507] 调用了test类方法
2014-10-06 07:26:55.553 a.out[653:507] 调用了test对象方法 0
封装第六个例子类方法练习
类计算器
类行为 求和,求平均值
bogon:04oc whome$ touch oc18.m
bogon:04oc whome$ open oc18.m
//类方法练习,计算器 #import <Foundation/Foundation.h> /* 设计一个计算器类 求和 求平均值 */ @interface JiSusnQi : NSObject + (int)sumOfNum1:(int)num1 andNum2:(int)num2; + (int)averageOfNum1:(int)num1 andNum2:(int)num2; @end
@implementation JiSusnQi + (int)sumOfNum1:(int)num1 andNum2:(int)num2 { return num1+num2; } + (int)averageOfNum1:(int)num1 andNum2:(int)num2 { int sum = [JiSusnQi sumOfNum1:num1 andNum2:num2]; return sum/2; } @end
int main(){ int a = [JiSusnQi averageOfNum1:10 andNum2:12]; NSLog(@"a=%d",a); return 0; }
bogon:04oc whome$ cc oc18.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 07:45:54.458 a.out[684:507] a=11
类方法注意事项,类方法不能自己调用自己,会进入死循环。
封装第七个例子self关键字 关于成员变量
bogon:04oc whome$ touch oc19.m
bogon:04oc whome$ open oc19.m
//self关键字 self是个指针 #import <Foundation/Foundation.h> @interface Person : NSObject { int _age; } - (void)setAge : (int)age; - (int)age; - (void)test; @end
@implementation Person - (void)setAge : (int)age{ //_age = age; self->_age = age; } - (int)age{ return self->_age; //return _age; } - (void)test{ //访问成员变量的方法 int age1 = _age; //当局部对象名称与成员变量重名。 //使用时报:local declaration of '_age' hides instance variable //[-Wshadow-ivar] int _age = 20; //NSLog(@"age:%d", _age); NSLog(@"age:%d",age1); //self的使用 //self:指向了对象调用者,代表着当期对象 NSLog(@"self->age:%d",self->_age); } @end
int main() { Person *p = [Person new]; [p setAge:10]; [p test]; return 0; }
bogon:04oc whome$ cc oc19.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 21:42:00.426 a.out[467:507] age:10
2014-10-06 21:42:00.430 a.out[467:507] self->age:10
封装第八个例子self关键字 关于类方法与对象方法
类 狗dog
类行为 叫和跑 bark,run
bogon:04oc whome$ touch oc20.m
bogon:04oc whome$ open oc20.m
//self关键字 关于类方法与对象方法
/*
self的用途
1.谁调用了当前方法,self就代表谁
self出现在对象方法中,self就代表对象
self出现在类方法中,self就代表类
2.在对象方法利用"self->成员变量名"访问当前对象内部的成员变量
3.[self 方法名]可以调用其他对象方法\类方法
*/
#import <Foundation/Foundation.h> @interface Dog :NSObject - (void)bark; - (void)run; + (void)bark; + (void)run; @end
@implementation Dog - (void)bark { NSLog(@"对象方法 汪汪汪"); } - (void)run { [self bark]; NSLog(@"对象方法 跑起来了"); } + (void)bark { NSLog(@"类方法 汪汪汪"); } + (void)run { [self bark]; NSLog(@"类方法 跑起来了"); } @end
int main() { Dog *dog = [Dog new]; [dog run]; [Dog run]; return 0; }
bogon:04oc whome$ cc oc20.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 22:34:25.917 a.out[530:507] 对象方法 汪汪汪
2014-10-06 22:34:25.922 a.out[530:507] 对象方法 跑起来了
2014-10-06 22:34:25.922 a.out[530:507] 类方法 汪汪汪
2014-10-06 22:34:25.923 a.out[530:507] 类方法 跑起来了
封装第九个例子self关键字 注意事项
类 Person 人
bogon:04oc whome$ touch oc21.m
bogon:04oc whome$ open oc21.m
//self的注意事项
/*
self的用途
1.谁调用了当前方法,self就代表谁
self出现在对象方法中,self就代表对象
self出现在类方法中,self就代表类
2.在对象方法利用"self->成员变量名"访问当前对象内部的成员变量
3.[self 方法名]可以调用其他对象方法\类方法
*/
#import <Foundation/Foundation.h> @interface Person : NSObject - (void)test; + (void)test; - (void)test1; + (void)test2; - (void)haha1; + (void)haha2; @end
@implementation Person - (void)test { NSLog(@"调用了-test方法"); //引发死循环 //[self test]; } + (void)test { NSLog(@"调用了+test方法"); //引发死循环 //[self test]; } - (void)test1 { [self test]; } + (void)test2 { [self test]; } - (void)haha1 { NSLog(@"调用了-haha1方法"); } + (void)haha2 { //这么调用是不对的,因为极sefl指向的是类不是对象 //[self haha1]; Person *p = [Person new]; [p haha1]; } + (void)haha3 { [self haha2]; } @end
int main(){ Person *p = [Person new]; [p test]; [Person test]; [p test1]; [Person test2]; [p haha1]; [Person haha2]; [Person haha3]; return 0; }
bogon:04oc whome$ cc oc21.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-06 23:48:10.305 a.out[584:507] 调用了-test方法
2014-10-06 23:48:10.308 a.out[584:507] 调用了+test方法
2014-10-06 23:48:10.308 a.out[584:507] 调用了-test方法
2014-10-06 23:48:10.309 a.out[584:507] 调用了+test方法
2014-10-06 23:48:10.310 a.out[584:507] 调用了-haha1方法
2014-10-06 23:48:10.311 a.out[584:507] 调用了-haha1方法
2014-10-06 23:48od0.315 a.out[584:507] 调用了-haha1方法
封装第十个例子 继承
类b继承类a
基类 动物类
猫,狗类 继承动物类
bogon:04oc whome$ touch oc22.m
bogon:04oc whome$ open oc22.m
//继承
/*
继承的好处:
1.抽取重复代码
2.建立了类之间的关系
3.子类可以拥有父类中的所有成员变量和方法
注意点
1.基本上所有类的根类是NSObject
*/
#import <Foundation/Foundation.h> @interface Animal : NSObject { int _age; double _weight; } - (void)setAge:(int)age; - (int)age; - (void)setWeight:(double)weight; - (double)weight; @end
@implementation Animal - (void) setAge:(int)age { _age = age; } - (int)age { return _age; } - (void)setWeight:(double)weight { _weight = weight; } - (double)weight { return _weight; } @end
//: Animal 继承了Animal,相当于拥有了Animal里面的所有成员变量和方法
// Animal称为Dog的父类
// Dog称为Animal的子类
@interface Dog : Animal @end
@implementation Dog @end
@interface Cat : Animal @end
@implementation Cat @end
int main(){ Dog *d = [Dog new]; Cat *c = [Cat new]; [d setAge:10]; NSLog(@"dog age=%d",[d age]); [c setAge:10]; NSLog(@"cat age=%d",[c age]); return 0; }
bogon:04oc whome$ cc oc22.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-07 00:41:54.872 a.out[648:507] dog age=10
2014-10-07 00:41:54.875 a.out[648:507] cat age=10
封装第十一个例子 继承的使用注意
查看NSObject.h
xcode右键->contents-developer-platforms-iphoneOS platform-developer-sdk-iphoneos6.0sdk-system-library-frameworks-Foundation.framework-Headers-NSObject.h
bogon:04oc whome$ touch oc23.m
bogon:04oc whome$ open oc23.m
//继承的使用注意
#import <Foundation/Foundation.h>
/*
注意事项
1.重写:子类重新实现父类中的某个方法,覆盖父类以前的做法
2.父类必须声明在子类的前面。
3.子类不能拥有和父类相同的成员变量
4.调用某个对象方法时,优先去当前对象中寻找,如果找不到去父类中寻找。
坏处:耦合性太强
*/
//Person @interface Person : NSObject { int _age; } - (void)setAge:(int)age; - (int)age; - (void)run; + (void)test; @end
@implementation Person - (void)setAge:(int)age { _age = age; } - (int)age { return _age; } - (void)run { NSLog(@"Person run"); } + (void)test { NSLog(@"Person +test"); } @end
//Student @interface Student : Person { int _no; //不允许子类和父类拥有相同名称的成员变量 //int _age; } @end
@implementation Student //重写:子类重新实现父类中的某个方法,覆盖父类以前的做法 - (void)run { NSLog(@"Person run"); } + (void)test { NSLog(@"Student +test"); } + (void)test2 { [self test]; } @end
int main(){ Student *s = [Student new]; //如果子类没有实现run才在父类中寻找。 [s run]; [Person test]; [Student test]; [Student test2]; return 0; }
bogon:04oc whome$ cc oc23.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-07 01:22:18.238 a.out[702:507] Person run
2014-10-07 01:22:18.242 a.out[702:507] Person +test
2014-10-07 01:22:18.243 a.out[702:507] Student +test
2014-10-07 01:22:18.244 a.out[702:507] Student +test
封装第十二个例子 继承的使用场合
bogon:04oc whome$ touch oc24.m
bogon:04oc whome$ open oc24.m
#import<Foundation/Foundation.h>
/*
继承的使用场合。
1.当两个类拥有相同属性和方法的时候,就可以将相同的东西抽取到一个父类中
2.当a类完全拥有b类中的部分属性和方法时,可以考虑让b类继承a类
a
{
int _age;
int _no;
}
b : a
{
int _weight;
}
//继承 :xx是xxx
//组合 :xxx拥有xxx
组合
A
{
int _age;
int _no
}
B
{
A *a;
int _weight;
}
*/
@interface Score : NSObject { int _cScore; int _ocScore; } @end @implementation Score @end @interface Student : NSObject { //组合 Score *_score; int _age; } @end
@implementation Student @end int main(){ return 0; }
bogon:04oc whome$ cc oc24.m -framework Foundation
封装第十三个例子 继承 super关键字
bogon:04oc whome$ touch oc25.m
bogon:04oc whome$ open oc25.m
//继承 super关键字
#import <Foundation/Foundation.h>
/*
僵尸
跳跃僵尸,舞王僵尸,铁桶僵尸
*/
/*
super的作用
1.直接调用父类中的某一个方法
2.super处在对象方法中,那么就会调用父类的对象方法。
3.super处在类方法中,那么就会调用父类的类方法。
使用场景
子类重写父类的方法时,想保留父类的一些行为。
*/
//僵尸 @interface Zoombie : NSObject - (void)walk; + (void)test; - (void)test; @end
@implementation Zoombie - (void)walk { NSLog(@"往前挪两步"); } + (void)test { NSLog(@"zoombie +test"); } - (void)test { NSLog(@"xoombie -test"); } @end
//跳跃僵尸 @interface JumpZoombie : Zoombie @end
@implementation JumpZoombie - (void)walk { NSLog(@"往前跳两下"); //super的使用,使用父类方法,不仅可以调用对象方法,还可以调用类方法 [super walk]; } + (void)haha { [super test]; } - (void)haha { [super test]; } @end
int main () { JumpZoombie *jz = [JumpZoombie new]; [jz walk]; [jz haha]; [JumpZoombie haha]; return 0; }
bogon:04oc whome$ cc oc25.m -framework Foundation
bogon:04oc whome$ ./a.out
2014-10-07 02:50:50.673 a.out[831:507] 往前跳两下
2014-10-07 02:50:50.677 a.out[831:507] 往前挪两步
2014-10-07 02:50:50.678 a.out[831:507] xoombie -test
2014-10-07 02:50:50.689 a.out[831:507] zoombie +test
封装第十四个例子 多态
多态,多种形态
bogon:04oc whome$ touch oc26.m
bogon:04oc whome$ open oc26.m
/*
多态
1.没有继承就没有多态
2.代码的体现:父类类型的指针指向子类对象
3
多态的好处
用一个父类指针变量就可以指向多个子类对象
多态的局限
父类类型的变量不能用来调用子类特有的方法(子类有,父类没有的方法),必须强转为子类类型变量后,才能直接调用子类特有的方法。
解决办法,强制转换
Dog *d = (Dog *)a;
*/
#import <Foundation/Foundation.h> @interface Animal : NSObject - (void)eat; @end
@implementation Animal - (void)eat { NSLog(@"eat"); } @end
//dog
@interface Dog : Animal @end
@implementation Dog - (void)eat { NSLog(@"dog eat"); } - (void)run { NSLog(@"dog run"); } @end
//cat
@interface Cat : Animal @end
@implementation Cat - (void)eat { NSLog(@"cat eat"); } @end
//多态的灵活使用
//如果参数中使用的是父类类型,可以传入父类,子类对象,调用方法时会检测对象的真实形象。
void feed(Animal *aa)
{
[aa eat];
}
int main() { //多种形态 //Dog类型 Dog *d = [Dog new]; //多态:父类指针指向子类对象 NSObject *n = [Animal new]; Animal *a = [Dog new]; NSObject *an = [Dog new]; //不合理的调用 Cat *c = [Animal new];//oc是弱语法,只有警告 Dog *dd = [Cat new]; NSString *s = [Cat new];//oc是弱语法,只有警告 //调用方法时会检测对象的真实形象。 [a eat]; //灵活使用 feed(d); feed(n); feed(an); feed(a); feed(c); feed(dd); //编译器会发出警告,因为编译器以为a是animal类型,只有运行时才会检测它的真实形态 [a run]; //强制类型转换 Dog *ddd = (Dog *)a; [ddd run]; return 0; }
bogon:04oc whome$ cc oc26.m -framework Foundation
oc26.m:65:10: warning: incompatible pointer types initializing 'Cat *' with an
expression of type 'Animal *' [-Wincompatible-pointer-types]
Cat *c = [Animal new];//oc是弱语法,只有警告
^ ~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/objc/NSObject.h:59:1: note:
class method 'new' is assumed to return an instance of its receiver type
('Animal *')
+ (id)new;
^
oc26.m:66:10: warning: incompatible pointer types initializing 'Dog *' with an
expression of type 'Cat *' [-Wincompatible-pointer-types]
Dog *dd = [Cat new];
^ ~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/objc/NSObject.h:59:1: note:
class method 'new' is assumed to return an instance of its receiver type
('Cat *')
+ (id)new;
^
oc26.m:68:15: warning: incompatible pointer types initializing 'NSString *' with
an expression of type 'Cat *' [-Wincompatible-pointer-types]
NSString *s = [Cat new];//oc是弱语法,只有警告
^ ~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/objc/NSObject.h:59:1: note:
class method 'new' is assumed to return an instance of its receiver type
('Cat *')
+ (id)new;
^
oc26.m:75:10: warning: incompatible pointer types passing 'NSObject *' to
parameter of type 'Animal *' [-Wincompatible-pointer-types]
feed(n);
^
oc26.m:49:19: note: passing argument to parameter 'aa' here
void feed(Animal *aa)
^
oc26.m:76:10: warning: incompatible pointer types passing 'NSObject *' to
parameter of type 'Animal *' [-Wincompatible-pointer-types]
feed(an);
^~
oc26.m:49:19: note: passing argument to parameter 'aa' here
void feed(Animal *aa)
^
oc26.m:81:8: warning: 'Animal' may not respond to 'run'
[a run];
~ ^
6 warnings generated.
bogon:04oc whome$ ./a.out
2014-10-07 03:57:59.265 a.out[940:507] dog eat
2014-10-07 03:57:59.267 a.out[940:507] dog eat
2014-10-07 03:57:59.267 a.out[940:507] eat
2014-10-07 03:57:59.268 a.out[940:507] dog eat
2014-10-07 03:57:59.268 a.out[940:507] dog eat
2014-10-07 03:57:59.269 a.out[940:507] eat
2014-10-07 03:57:59.269 a.out[940:507] cat eat
2014-10-07 03:57:59.270 a.out[940:507] dog run
2014-10-07 03:57:59.270 a.out[940:507] dog run
[align=center]------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------[/align]
相关文章推荐
- 黑马程序员:OC三大特性
- 黑马程序员——OC面向对象三大特性——封装,继承,多态。
- 黑马程序员————OC面向对象_三大特性之封装
- 黑马程序员_OC语言之面向对象的三大特性(封装、继承、多态)
- 黑马程序员——OC基础——类的三大特性(2)
- 黑马程序员-OC对象的三大特性
- 黑马程序员—OC之三大特性
- 黑马程序员—OC语言基础—面向对象的三大特性(1)
- 黑马程序员--07 OC 三大特性
- 黑马程序员(OC的三大特性)
- 黑马程序员——OC语言三大特性
- 黑马程序员-OC的三大特性:封装、继承、多态
- 黑马程序员——OC语言基础篇---面向对象之三大特性
- 黑马程序员_iOS开发之OC之面向对象之三大特性封装、继承和多态
- 黑马程序员————IOS学习笔记 第3篇 OC面向对象三大特性(1)
- 黑马程序员———OC学习的第二天(三大特性)
- 黑马程序员------OC三大特性
- 黑马程序员——OC基础——面向对象的三大特性(一)
- 黑马程序员——OC面向对象三大特性——封装,继承,多态。
- 黑马程序员-OC-三大特性