Objective-C通过一套全新语法,在C语言基础上添加了面向对象特性。Objective-C的语法中频繁使用方括号,而且不吝于写出极长的方法名,这通常令许多人觉得此语言较为冗长。其实这样写出来的代码十分易读,只是C++或Java程序员不太能适应。
Objective-C语言学起来很快,但有很多微妙细节需注意,而且还有许多容易为人所忽视的特性。另一方面,有些开发者并未完全理解或是容易滥用某些特性,导致写出来的代码难于维护且不易调试。本章讲解基础知识,后续各章谈论语言及其相关框架中的各个特定话题。
和C++,Java一样,Objective-C也是面向对象语言,但是它们在许多方面都有差别。差别在于Objective-C使用的是消息结构而非函数调用,Objective-C语言由Smalltalk1演化而来的,Smalltalk是消息型语言的鼻祖
//Messaging(Objevtive-C)
Object *obj = [Object new];
[obj performWith:parameter1 and:parameter2];
//Function calling(C++)
Object *obj = new Object;
obj->perform(parameter1, parameter2);
消息结构和函数调用的关键差别在于:使用消息结构的语言,其运行所应执行的代码由运行环境来决定;而使用函数调用的语言,则由编译器决定。对于函数结构,如果范例代码的调用函数是多态的,那么就在运行时按照虚方法表来查出来到底执行哪个函数,而采用消息结构的语言,不管是否为多态总是在运行时才回去查找所要执行的方法。
NSString *someString = @"The string";
例如上述代码,声明了一个someString 的变量,此变量为指向NSString的指针,因为OC声明变量基本上都为指针变量,所以OC对象所占内存总是分配在“堆空间”(heap space)中,而绝不会分配在“栈”(stack)上
如果再次创建一个对象Same,那么这两个对象队徽分配在堆中,它们同时指向了堆中的NSString实例
NSString *someString = @"The string";
NSString *anotherString = someString;
Objective-C为C语言添加了面向对象特性,是其超集。Objective-C使用动态绑定的消息结构,也就是说,在运行时才会检查对象类型。接收一条消息之后,究竟应执行何种代码,由运行期环境而非编译器来决定。
理解C语言的核心概念有助于写好Objective-C程序。尤其是要掌握内存模型和指针。
在一年前我用C语言写学生管理系统的时候,遇到了一个当时无法解决的问题,当时我利用了多文件编写,把登录,学生,教师,管理员分为了四个不同的.h文件进行分开写,一切都还算顺利,但是有个返回上一步函数,需要在.h文件里调用.m主文件的函数,如果引入头文件,就会导致程序莫名其妙崩溃,当时也无法解决这个问题,在学习了这一部分的内容,就能明白当时崩溃的原因。
而当你需要实现EOCEmployer接口的全部细节时候只需要在实现文件里添加#import "EOCEmployer.h"即可:
#import "EOCPerson.h"
#import "EOCEmployer.h"
@implementation EOCPerson
@end
向前声明:
//EOCPerson.h
#import <Foundation/Foundation.h>
//此方法即为“向前声明”(可以实现不用引用该类的头文件就可以创建该类的属性)
@class EOCEmplyer;
@interface EOCPerson:NSObject
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
//创建的EOCEmployer类型属性
@property (nonatomic, strong) EOCEmployer *employer;
@end
字面数值:
NSNumber *number = [NSNumber numberWithInt:1];
字面量数值:
NSNumber *number = @1;
字面数组:
NSArray *array = [NSArray arrayWithObjects:@"1", @"2", @"3", @"4", nil];
字面量数组:
NSArray *array = @[@"1", @"2", @"3", @"4"];
对于字面量的话,需要注意的是,如果字面量初始化的有nil,就会报错,并且还需要注意,字面量初始化默认的是不可变的,如果需要初始化可变类型容器,就不能使用字面量进行初始化。
//不用字面量初始化的数组
NSString *string = [array objectAtIndex:1];
//字面量初始化的数组
NSString *string = array[1];
宏定义的方法:
#define iOS 666
类型常量的方法:
static const NSString* iOS = @"666";
定义使用extern关键字
在头文件
extern NSString *const Name;
在实现文件
NSString *const Name = @"zxb10";
枚举只是一种常量命名方式,某个对象所经历的各个状态、定义选项或者把逻辑含义相似的一组状态码都可以放入一个枚举集里。
编译器会为枚举分配一个独有的编号,从0开始,每个枚举递增1,也可以手动设置某个枚举成员对应的值,后面的枚举值一次加1。
可以指明枚举用的何种底层数据类型,这样编译器清楚底层数据类型的大小,可以向前声明枚举类型。
UIButton的状态:
typedef NS_ENUM(NSInteger, UIButtonRole) {
UIButtonRoleNormal,
UIButtonRolePrimary,
UIButtonRoleCancel,
UIButtonRoleDestructive
} API_AVAILABLE(ios(14.0));