您的位置:首页 > 编程语言 > C语言/C++

黑马程序员——OC语言基础篇---核心语法

2015-04-15 15:51 429 查看
------Java培训、Android培训、iOS培训、.Net培训 期待与您交流!
-------

本篇主要通过一些小案例来讲述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;
@end
Person.m里的内容:

#import "Person.h"
@implementation Person
- (void)setAge:(int)age
{
_age = age;
}

- (int)age
{
return _age;
}
@end
p.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;
}
@end
Student类也进行了重写,在把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)
@end
test是分类名,实际开发中一般会按功能来命名
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,搞定了!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: