在学习C的同时,我们可以对比着来进行Objective-C,本篇文章主要对Objective-C进行一下简单的介绍,以对Objective-C有一个大致的了解。
Objective-C是一门基于C语言的面向对象语言,可以说是ANSI C的超集,而且是严格意义上的超集,它是在C语言的基础上加上了面向对象的技术,所有C语言可以实现的它都可以实现,反之则不成立,如果你接触过C语言那么理解Objective-C的一些知识点会容易很多,这里之所以说是一些知识点,是因为在Objective-C中有许多framework是基于C语言或C++来编写的。如果你之前一点Objective-C都没有接触过,可能会对Objective-C的语法特点感到不适应,不过这些语法特点都是很容易被人理解的,因此相信你很快就会适应并掌握这门技术,因为这是一门人性化的语言。
Objective-C代码文件的扩展名分别为:.h(头文件),.m(可包含Objective-C和C语言语句),.mm(除了可包含Objective-C和C之外还可以包含C++语句)
首先引入一个例子,可以和C语言开篇引入的例子做一下比较
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
这段代码是使用Xcode创建一个CommandLine工程时自动生成的代码,与C语言类似,也有头文件的引入,也有main()函数,也有返回值等,我们先来分析一下这段代码。
#import <Foundation/Foundation.h>//头文件的引入
在Objective-C中头文件的引入与C语言中的头文件引入所使用的关键字有所不同,在C语言中使用的是include关键字,而在这里使用的却是import,这两者的区别主要是import关键字可以保证所引用的头文件只被包含一次,而include可能造成文件的重复包含,且可能造成交叉编译。因此在C语言中为保证头文件不被重复包含通常会使用宏定义的方式来避免这种事件的发生,如:
#ifndef _TEST_H_
#define _TEST_H_
//insert declaration here
#endif
而在Objective-C中使用#import来引入头文件则不必添加以上语句。
关于#include<>和#include""的使用我在C语言第一篇中说过了,同样在Objective-C中的#import也有这两种用法,与C语言中的用法是一样的,#import<xxx.h>是直接在相关类库中查找xxx.h文件,而#import"xxx.h"是先在当前工程的工程目录下查找xxx.h文件,若没有则到相关类库中查找,两者相同的部分是在查找到xxx.h文件后会将xxx.h中的所有内容编译到当前文件中。
在IOS7之后Objective-C又引入了@class xxxClass的引入方式和@import xxxFramework 的引入方式。 @class xxxClass一般用于头文件中需要声明该类的某个实例变量的时候用到,若要访问该类的某个实例的属性变量在m文件中还是需要使用#import来引入该类的。
import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。
在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。
如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。
所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来。
而@import是用来引入某一类库的,从而不必到Build Phases下的Link Binary With Libraries下查找添加该库文件了。
int main(int argc, const char * argv[])
这里的main函数中有两个参数,其实C语言中的main函数里也有这两个参数其中argc是命令行总的参数个数,argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数便是从命令行输入的参数,例如在linux中的ls 命令 ls -l,argv[1...n]里保存的便相当于-l类参数。一般在窗口程序中很少用到这两个参数,因此这里的这两个形参可以不写。
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
这里我们又遇到一个新我关键字@autoreleasepool,字面意思为自动释放池,这里的autoreleasepool是ARC(Automatic Reference Counting,自动引用计数)模式下的一种内存管理方式,在Objective-C中三种内存管理方式,第一种是MRR(Manual Retain Release手动引用和释放,另外一种说法是MRC Manual Reference Counting,手动引用计数)Objective-C中最原始的内存管理方式,所需内存必须手动分配手动释放,第二种是ARC是Objective-C中引入的新的内存管理方式,内存的释放不必手动管理,这也是官方推荐使用的方式;第三种是GC(Garbage Collection)垃圾收集机制,GC只有在OS X上被支持,在IOS系统中是不被支持的。
NSLog()函数与C语言中的printf()函数是对应的,功能也是在控制台格式化输出语句,要注意的是这里输出内容的字符串是放到@""的双引号里面的,双引号前有@符号,这是为了区分C语言的字符串与Objective-C的字符串。
return 0;
这里的return语句同C语言中的return语句是一样的,与函数返回值类型是对应的。
这只是一个简单的案例,Objective-C中的知识点当然不只这些,Objective-C是面向对象的语言,因此在Objective-C中万物皆对象,Objective-C中的数据对象我们将在以后慢慢接触到,在接触到这些数据对象之前我们大可使用C中的基本数据类型。
面向对象语言最大特点就是类,Objective-C中也有类的定义,学习类和对象之前我们先来了解一下什么是类,什么是对象。
先来理解一下什么是对象,简单点说,对象就是一个事物,多个相同的事物同属于一个类,比如,你有一辆玛莎拉蒂,它显然是一个对象,这个对象属于汽车这个类。在面向对象的程序设计中,你的这辆玛莎拉蒂也叫做一个实例,一个汽车类的实例,你的这辆车有自己的颜色、外形、内饰、发动机等这些叫做汽车的属性,这辆汽车可以驾驶,要加油,要保养这些对实例进行操作称为汽车实例要调用的方法,在某些情况下,方法可以应用于类的实例或类本身,应用于类的实例的方法,如驾驶,称为实例方法,面应于于类的方法,如制造一辆新的汽车以产生一个新的实例的方法,称为类方法,这个生产一个新的类的实例的方法在面向对象中称为构造方法。
让我们通过代码来体验上面这段话的具体含义。
//Car.h
#import <Foundation/Foundation.h>
@interface Car : NSObject
@property (nonatomic, copy) NSString *name;
+ (Car*)createANewCar; //生产一辆新车
- (void)drive; //开车
@end
//Car.m
#import "Car.h"
@implementation Car
- (instancetype)init{
if (self = [super init]) {
self.name = @"玛莎拉蒂";
}
return self;
}
+ (Car*)createANewCar //生产一辆新车
{
return [[Car alloc] init];
}
- (void)drive //开车
{
NSLog(@"driving!");
}
@end
//main.m
#import <Foundation/Foundation.h>
#import "Car.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Car *car1 = [Car createANewCar];
[car1 drive];
}
return 0;
}
在这里我们定义了一个名为Car的类,它有四个属性变量和一个类方法以及五个实例方法。Car.h文件中定义了整个类,我们一行行来看,来认识一下类的结构。
第一行是注释,在Objective-C中注释有两种方式一种是双斜线//后面跟着要注释的内容,这称为行注释,注释中不能有换行符;另一种是斜线和星号的组合/*这里写下注释内容*/,常用于段落注释。
第二行是引入Foundation类库,这里面定义了一些基础变量以及函数。
@interface Car : NSObject
//这里定义成员变量、属性以及方法
@end
这两行是对类的声明,以@interface开头以@end结尾,形式为@interface 类名 : 父类名。在@interface 和 @end之间定义的是类的成员变量,属性和方法。
@interface Car : NSObject下面跟着的那一行称为类的属性变量,用于保存实例的属性。
再向下
+ (Car*)createANewCar;
以+号开头的方法称为类方法也称为静态方法
- (void)drive;
以-号开头的方法称为实例方法
下面来看Car.m文件,它是源码文件,里面包含对Car类的实现
@implementation Car
//这里写类方法以及实例方法的实现
@end
类的实现以@implementation 类名 开头,以@end结尾,有类的声名就必须有类的实现,无论这个类有没有要实现的方法,都必须有
@implementation 类名
@end
在本例中实现部分的第一个函数就是Objective-C中的构造函数,它的功能便是初始化当前实例对象。
在main.m文件中使用我们创建好的Car的类,首先要导入Car.h的头文件,然后使用Car来创建一个新的实例car1
Car *car1 = [Car createANewCar];
//这里也可以使用以下方法来创建一个新的实例,创建的效果是一样的
Car *car2 = [[Car alloc]init];
Car *car3 = [Car new];
值得注意的是,Objective-C中定义类的实例时都应带有*号。
创建完对象之后,我们就可以使用这些对象来调用他们自己的方法了。
比如上面的用法 [car1 drive]; 你也可以分别调用[car2 drive];[car3 drive]...试一下吧。
总结:
在Objective-C中引入头文件有#import"xxx.h",#import<xxx.h>,@import framework,@class Class,几种形式,各种形式之间是有差别的。
在Objective-C中内存管理机制分为MRR,ARC和GC三种方法。
Objective-C是面向对象的语言。
在Objective-C中类的定义和实现必须同时存在,如果只定义了类而没有对应的实现则会在编译时会报错。
Objective-C类的定义形式为@interface 类名 : 父类名,然后声明其变量和方法最后要以@end结尾。类的实现形式为@implementation 类名 然后是方法的实现最后也要以@end结尾。