黑马程序员——OC语言基础篇---核心语法
2015-04-15 15:51
429 查看
------Java培训、Android培训、iOS培训、.Net培训 期待与您交流!
-------
本篇主要通过一些小案例来讲述OC的一些核心语法,包括点语法、property、构造方法和分类等,本章内容的开发工具是Xcode,不再使用前面的终端来编译和运行程序了。
我们来看一下它的用法:
这里首先利用Xcode创建了一个Person类
Person.h里的内容:
int a = p.age;而这一句是调用了_age的get方法
@private 只能在当前类的对象方法中访问(子类不能直接访问,但是内存中是有这个变量的)
@protected 能在当前类和子类的对象方法中直接访问
默认情况是protected
@package 两个类处于同一个框架中,就能直接访问对象的成员变量
注意点
声明中的成员变量默认是protected
实现中也是可以定义成员变量,但是成员变量是private的,并且实现中不能定义和@interface中同名的成员变量
不声明直接写实现也是可以的,但是一般不会这样写,有声明有实现程序才会完整
OC中是单继承,一个类只能继承一个父类
比如上面点语法中Person的声明就可以变成
代码一下精简好多,还可以更精简一点,成员变量的定义也可以省略,Xcode可以帮我们自动生成 _age 成员变量。
但是注意如果成员变量的声明不写,再使用 @synthesize age;这样是不对的,因为如果不写后面的成员变量,默认会访问名字相同的变量。
现在这些烦恼都没有了,synthesize也可以不用写了,直接使用@property,就OK了,如果只写了@property,默认生成和访问带下划线的成员变量
有两个注意点:
(1)如果setter和getter方法自定义了,那么调用的是自定义的,而不是Xcode自动生成的
(2)如果setter和getter都手动实现了,Xcode是不会自动生成带下划线的成员变量
不贴图了,还是直接上代码吧
main.m
此时,id可以看做是Person类
运行结果:
2015-04-15 16:47:56.426 id[3562:303] d = 10,d2 = 20
下面通过程序来看看如何重写init方法
首先,创建两个类Person和Student,Student继承Person
main.m
**************************************************************************************************************************************************************************************************
Person类
**************************************************************************************************************************************************************************************************
Student类
运行结果是:
2015-04-15 16:56:34.895
构造方法[3630:303] 10,p.age = 10
2015-04-15 16:56:34.897
构造方法[3630:303]
年龄是10,学号是1
2015-04-15 16:56:34.897
构造方法[3630:303] 20
自定义构造方法规范
1.一定以 - 开头
2.返回 id 类型
3.方法名一般以initWith开头
自定义构造方法也是需要调用父类的init方法的
作用
可以在不改变原来类内容的基础上,可以为类增加一些方法
使用注意
1.分类只能扩充方法,不能增加成员变量
2.分类可以访问原来类中声明的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法无法使用
4.方法调用的优先级:分类 --> 原来类 --> 父类
其实类也是一个对象,Class类型的对象
类对象就是指类
会先把类加载进内存,类只会加载一次
获取class对象的两种方法
1 Person *p = [[Person alloc] init];
class c = [p class];
2 [Person class];
所有的对象获取的类对象都是同一个
类的加载 当程序启动的时候,就会加载一次项目中所有的类和分类,类加载完毕后就会调用每个类和分类的+load方法,只会调用一次(+load不区分类和分类,都会调用)
初始化 当第一次使用这个类的时候,就会调用一次+initialize(如果分类中有,只会调用分类中的)
创建两个类,Person(父类)和Student(子类),并为Person创建一个Category
Person.m
Student.m
Person+test.h(分类,注意分类只能扩充方法,不能扩充成员变量)
Person+test.m
其实上面的代码就是为所有的类和分类重写了 +load和 +initialize方法
我们来看看运行结果:
2015-04-15 17:59:15.821
类的本质[4008:303] PERSON-load
2015-04-15 17:59:15.822
类的本质[4008:303] STUDENT-load
2015-04-15 17:59:15.823
类的本质[4008:303] test-load
2015-04-15 17:59:15.823
类的本质[4008:303] test-initialize
2015-04-15 17:59:15.823
类的本质[4008:303] student-initialize
这说明了程序在运行时确实将所有的类和分类加载进来,但是调用+initialize却是使用的时候才会调用,而且如果分类中有该方法的重写的话是不会调用原来类的initialize方法的,本段代码中Person的initialize方法就没有调用,而创建的时Student对象(多态),所有它的方法被调用了
定义一个Person类,它有如下成员变量
2015-04-15 18:11:47.339 description[4137:303]
<Person: 0x100107300>
上面结果打印的时类名和地址
那么怎样才能打印出我需要的结果呢?
先来看看这句NSLog(@"\n%@",p);,这句话会调用系统的description方法,那么我们只要重写这个方法就可以了。
在Person.m中重写该方法:
[NSString stringWithFormat:@"年龄是%d,姓名是%@",self.age,self.name];这一句是指按照某种格式创建一个NSString对象
现在,我们再来看看结果:
2015-04-15 18:16:27.463 description[4163:303]
年龄是20,姓名是Jack
OK,搞定了!
-------
本篇主要通过一些小案例来讲述OC的一些核心语法,包括点语法、property、构造方法和分类等,本章内容的开发工具是Xcode,不再使用前面的终端来编译和运行程序了。
点语法
在学习其他语言的时候,经常可以见到 xxx.xxx,OC中也有类似的使用方法,被称作点语法,但其本质上却和其他语言不太相同,它利用了编译器特性,实际上是setter和getter。我们来看一下它的用法:
这里首先利用Xcode创建了一个Person类
Person.h里的内容:
#import <Foundation/Foundation.h> @interface Person : NSObject { int _age; } - (void)setAge:(int)age; - (int)age; @endPerson.m里的内容:
#import "Person.h" @implementation Person - (void)setAge:(int)age { _age = age; } - (int)age { return _age; } @endp.age = 10;这一句是调用了_age的set方法
int a = p.age;而这一句是调用了_age的get方法
成员变量的作用域
@public 只要有对象,任何位置都可以直接访问成员变量@private 只能在当前类的对象方法中访问(子类不能直接访问,但是内存中是有这个变量的)
@protected 能在当前类和子类的对象方法中直接访问
默认情况是protected
@package 两个类处于同一个框架中,就能直接访问对象的成员变量
注意点
声明中的成员变量默认是protected
实现中也是可以定义成员变量,但是成员变量是private的,并且实现中不能定义和@interface中同名的成员变量
不声明直接写实现也是可以的,但是一般不会这样写,有声明有实现程序才会完整
OC中是单继承,一个类只能继承一个父类
@property和@synthesize
之前有学习过set方法和get方法,写起来实在太麻烦,每个成员变量都需要写set和get方法,的确给我们带来很大的麻烦,所以有了@property和@synthesize,可以省去我们的麻烦。比如上面点语法中Person的声明就可以变成
#import <Foundation/Foundation.h> @interface Person : NSObject { int _age; } @property int age; @end实现可以变成
#import "Person.h" @implementation Person @synthesize age = _age; @end
代码一下精简好多,还可以更精简一点,成员变量的定义也可以省略,Xcode可以帮我们自动生成 _age 成员变量。
但是注意如果成员变量的声明不写,再使用 @synthesize age;这样是不对的,因为如果不写后面的成员变量,默认会访问名字相同的变量。
现在这些烦恼都没有了,synthesize也可以不用写了,直接使用@property,就OK了,如果只写了@property,默认生成和访问带下划线的成员变量
有两个注意点:
(1)如果setter和getter方法自定义了,那么调用的是自定义的,而不是Xcode自动生成的
(2)如果setter和getter都手动实现了,Xcode是不会自动生成带下划线的成员变量
id
id是一种类型,万能指针,不带 *,能够指向任何的对象不贴图了,还是直接上代码吧
main.m
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { id d = [Person new]; Person *d2 = [Person new]; d2.age = 20; [d setAge:10]; NSLog(@"d = %d,d2 = %d",[d age],d2.age); } return 0; }
此时,id可以看做是Person类
运行结果:
2015-04-15 16:47:56.426 id[3562:303] d = 10,d2 = 20
构造方法
(1)构造方法的init方法重写
上面在创建一个对象的时候用的是new方法,这个不好,一般我们会使用alloc和init方法来创建和初始化一个对象,而init方法一般也会进行重写,来达到我们满意的初始化效果。下面通过程序来看看如何重写init方法
首先,创建两个类Person和Student,Student继承Person
main.m
#import <Foundation/Foundation.h> #import "Person.h" #import "Student.h" int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [Person new]; /* 完整的创建一个可用的对象 1.分配存储空间 +alloc 2.初始化 -init */ Person *p1 = [[Person alloc] init]; NSLog(@"%d,p.age = %d",p1.age,p.age); Student *s1 = [[Student alloc] init]; NSLog(@"年龄是%d,学号是%d",s1.age,s1.no); Student *d1 = [[Student alloc] init]; d1.age = 20; NSLog(@"%d",d1.age); } return 0; }
**************************************************************************************************************************************************************************************************
Person类
#import <Foundation/Foundation.h> @interface Person : NSObject @property int age; @end
#import "Person.h" @implementation Person - (instancetype)init { //1.调用父类的init方法并且赋值给self //返回当前对象:初始化父类中的成员变量,self //2.判断self不为空,则是初始化成功 if (self = [super init]) { _age = 10; } //3.返回初始化的对象,也就是self return self; } @end上面就是对Person类的init方法进行重写,在调用了父类的init方法之后,编写自己需要初始化的内容
**************************************************************************************************************************************************************************************************
Student类
#import "Person.h" @interface Student : Person @property int no; @end
#import "Student.h" @implementation Student - (instancetype)init { if (self = [super init]) { _no = 1; } return self; } @endStudent类也进行了重写,在把Person把年龄初始化为10之后,又把学号初始化为1。
运行结果是:
2015-04-15 16:56:34.895
构造方法[3630:303] 10,p.age = 10
2015-04-15 16:56:34.897
构造方法[3630:303]
年龄是10,学号是1
2015-04-15 16:56:34.897
构造方法[3630:303] 20
(2)自定义构造方法
自定义构造方法就是自己写一个初始化的方法。自定义构造方法规范
1.一定以 - 开头
2.返回 id 类型
3.方法名一般以initWith开头
- (id)initWithName:(NSString *)name AndAge:(int)age { if (self = [super init]) { _name = name; _age = age; } return self; }
自定义构造方法也是需要调用父类的init方法的
Category(分类)和类的本质
(1)分类
可以给某一个类扩充一些方法,不修改原来类的代码作用
可以在不改变原来类内容的基础上,可以为类增加一些方法
使用注意
1.分类只能扩充方法,不能增加成员变量
2.分类可以访问原来类中声明的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法无法使用
4.方法调用的优先级:分类 --> 原来类 --> 父类
(2)类的本质
类的本质其实类也是一个对象,Class类型的对象
类对象就是指类
会先把类加载进内存,类只会加载一次
获取class对象的两种方法
1 Person *p = [[Person alloc] init];
class c = [p class];
2 [Person class];
所有的对象获取的类对象都是同一个
类的加载 当程序启动的时候,就会加载一次项目中所有的类和分类,类加载完毕后就会调用每个类和分类的+load方法,只会调用一次(+load不区分类和分类,都会调用)
初始化 当第一次使用这个类的时候,就会调用一次+initialize(如果分类中有,只会调用分类中的)
(3)综合应用
创建两个类,Person(父类)和Student(子类),并为Person创建一个Category
Person.m
#import "Person.h" @implementation Person + (void)load { NSLog(@"PERSON-load"); } + (void)initialize { NSLog(@"person-initialize"); } @end
Student.m
#import "Student.h" @implementation Student + (void)load { NSLog(@"STUDENT-load"); } + (void)initialize { NSLog(@"student-initialize"); } @end
Person+test.h(分类,注意分类只能扩充方法,不能扩充成员变量)
#import "Person.h" @interface Person (test) @endtest是分类名,实际开发中一般会按功能来命名
Person+test.m
#import "Person+test.h" @implementation Person (test) + (void)load { NSLog(@"test-load"); } + (void)initialize { NSLog(@"test-initialize"); } @end
其实上面的代码就是为所有的类和分类重写了 +load和 +initialize方法
我们来看看运行结果:
2015-04-15 17:59:15.821
类的本质[4008:303] PERSON-load
2015-04-15 17:59:15.822
类的本质[4008:303] STUDENT-load
2015-04-15 17:59:15.823
类的本质[4008:303] test-load
2015-04-15 17:59:15.823
类的本质[4008:303] test-initialize
2015-04-15 17:59:15.823
类的本质[4008:303] student-initialize
这说明了程序在运行时确实将所有的类和分类加载进来,但是调用+initialize却是使用的时候才会调用,而且如果分类中有该方法的重写的话是不会调用原来类的initialize方法的,本段代码中Person的initialize方法就没有调用,而创建的时Student对象(多态),所有它的方法被调用了
description
如果我想要打印类里面的所有变量,而不是一个一个取出来打印,该如何做呢?定义一个Person类,它有如下成员变量
@property int age; @property NSString *name;main.m中有如下代码,那么究竟会打印什么呢?
Person *p = [[Person alloc] init]; p.age = 20; p.name = @"Jack"; NSLog(@"\n%@",p);//调用description方法结果是:
2015-04-15 18:11:47.339 description[4137:303]
<Person: 0x100107300>
上面结果打印的时类名和地址
那么怎样才能打印出我需要的结果呢?
先来看看这句NSLog(@"\n%@",p);,这句话会调用系统的description方法,那么我们只要重写这个方法就可以了。
在Person.m中重写该方法:
@implementation Person - (NSString *)description { NSString *s = [NSString stringWithFormat:@"年龄是%d,姓名是%@",self.age,self.name]; return s; } @end
[NSString stringWithFormat:@"年龄是%d,姓名是%@",self.age,self.name];这一句是指按照某种格式创建一个NSString对象
现在,我们再来看看结果:
2015-04-15 18:16:27.463 description[4163:303]
年龄是20,姓名是Jack
OK,搞定了!
相关文章推荐
- 黑马程序员-OC语言之核心语法
- 黑马程序员—OC语言基础—核心语法小结
- 黑马程序员-OC语言核心语法(1)
- 黑马程序员——OC语言核心语法
- 黑马程序员——OC语言基础篇---基本语法、类
- 黑马程序员-OC语言核心语法(2)构造方法
- 黑马程序员-OC语言核心语法(3)(分类、SEL、类本质)
- 黑马程序员—OC语言基础—基础语法知识
- 黑马程序员_OC_核心语法
- 黑马程序员 -- OC语言 NSString使用 点语法 构造 分类
- 黑马程序员----OC基础--核心语法、关键字
- 黑马程序员 OC语言 - 4 OC特有语法
- 黑马程序员--IOS入学学习--8-OC核心语法
- 黑马程序员_OC面向对象之核心语法
- 黑马程序员-----------ios培训 oc核心语法一
- 黑马程序员——OC语言基本语法
- 黑马程序员——OC语言基础篇---内存管理
- 黑马程序员-iOS基础-Objective-C基础(四)OC开发技巧及核心语法(上)
- 黑马程序员——OC中的核心语法
- 黑马程序员-OC语言基础:面向对象语法 二