从C++到OC,快速掌握 OC语法
从C++到OC,快速掌握 OC语法
[toc]
学习Objective-C 的笔记,有 C/C++ 基础的同学阅读文章此可以快速掌握 OC。
Xcode 快捷键
格式化代码:Command + A 全选(选中需要格式的代码段) 再 Ctrl + i 格式化代码
C 和 OC 的区别
由于 OC 的底层是 C 语言,所以 OC 和 C 完全兼容,在编程过程中,OC 和 C 可以混合使用。
分析一下一段最基本的 OC 代码:
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Hello, World!");
return 0;
}
在 OC 中,
#import
命令用来引入头文件。与 C 语言中的#include
相比,#import
能够保证头文件只被引入一次,也就是说,只有第一次引入有效,后续对同一文件的引入都会被忽略。而在 C 语言中,每次使用 #include 命令都会将头文件的内容引入一次,所以在头文件中必须使用#ifndef
和#endif
宏来保证头文件只被编译一次Foundation/Foundation.h
是 Foundation 框架的头文件,只要引入了它,就可以使用 Foundation 框架的功能。Foundation 是 OC 语言的基础框架,它提供了 OC 专有的基本数据类型(如字符串、数组、时间日期等),提供了多线程、网络连接、文件操作、本地数据存储等常用功能。Foundation.h 就像 C 语言中的 stdio.h,一般都需要引入
NSLog() 是 OC 中的格式化输出函数,相当于 C 语言中的 printf() 的升级版,不仅可以用来输出 C 语言中的数据,还可以输出 OC 中的数据。
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Hello, World!");
int a = 100;
float b = 3.14;
char *str = "hello, c";
NSString *NSstr = @"hello,object-c";
NSLog(@"\n a: %d\n b: %f\n str: %s\n OC str: %@",a, b, str, NSstr);
return 0;
}
@
符号没有实际含义,只是用来作为 OC 字符串的特有标志。在 OC 中,字符串前面都要加@
,如果不加,就变成了 C 语言中的字符串,就要使用字符指针或字符数组来定义
OC 中的数据类型和数据结构
因为 OC 是完全兼容 C 的,所以 C 中的数据类型都可以在 OC 中使用。
先来看看 C 中有什么数据类型
- C 语言数据类型
- 基本类型
- 数值(int、long、float、double)
- 字符串(char)
- 构造类型
- 数组
- 结构体(struct)
- 共用体(union)
- 枚举(enum)
- 指针类型
- 空类型void
- 基本类型
很明显 C 中的数据类型有些少,当我们需要用到哈希表这样的数据结构的时候,就需要我们自己手写一个,OC 明显考虑到这个麻烦,所以添加了很多便于使用的数据结构。
比如有 NSObject、NSString(NSMutableString)、NSArray(NSMutableArray)、NSDictionary(NSMutableDictionary)、NSSet(NSMutableSet)、NSAttributedString(NSMutableAttributedString)
这些数据结构,使开发效率能够提高。
这些数据结构是由 Cocoa Foundation 框架提供的集合类,这些集合类中只可以放入对象,不能放入基本类型的数据。所以 Cocoa 提供了包裹类
- NSNumber 类来包装 int、long、char 等基本数据类型,使其可以放入集合类中。
- NSValue 可以将结构体、枚举、指针这些复杂的数据类型转换为对象放入集合类中。
- NSNull 可以将 nil 包裹之后放入集合类中。
提取包裹类中的值
使用下列的方法可以提取出 NSNumber 实例中的 NSInteger 的值
-(NSInteger) integerValue
需要注意的是:NSInteger 不是一个对象,而是基本数据类型的 typedef
OC 中的属性声明
一般来说,属性是指一个对象的属性或者特性(也就是变量和方法)

属性的声明有一些规律:
自动生成访问方法:
能够为声明的实例变量自动生成访问方法。既可以同时生成 getter 方法和 setter方法,也可以只生成 getter,也可以手动定义访问方法。
自动生成实例变量:
如果不存在同名的实例变量的话,在生成访问方法的同时,也会自动生成同名的实例变量。
更简单的调用访问方法
可以通过
.
操作符来访问调用方法。
@property 的几种常用修饰词
nonatomic 和 atomic
nonatomic:非原子性,涉及到多线程的相关知识。访问方法被 nonatomic 修饰的情况下,意味着它执行过程中可以被打断,如果多个线程同时调用 getter 或者 setter 方法,那么就会出现值丢失或内存泄漏等错误
atomic (默认):原子性。和 nonatomic 正好相反,它对属性的访问进行了限制,保护了声明属性的安全,缺点就是:访问效率低,速度慢。
assign、copy、retain、unsafe_unretained、strong、weak
assign:单纯赋值,可用于基础数据类型和对象类型
copy:复制对象,使用对象的副本进行赋值
retain:进行保持操作
release:进行释放操作
unsafe_unretained:同 assign 一样
strong:强引用,同 retain 一样,用于 ARC
weak:弱引用,用于 ARC
readonly和readwrite
readwrite(默认):它代表这个属性即可以读,也可以写(可以调用它的 get 和 set 方法)
readonly:和 readwrite 不同,它代表这个属性只能读,不能进行写操作(只能调用 get 方法,不能调用 set 方法)
赋值时的选项
OC 中类和对象
OC 中的类和 C 中的结构体功能类似,但是 C 只能在结构体里面定义不同类型的变量,而 OC 可以在类里面定义变量和方法,和 C++ 里面的类相似。
首先来看一下 C 中的结构体
#include <stdio.h>
struct Student {
char *name;
int age;
float score;
};
void display(struct Student stu){
printf("%s的年龄是:%d,成绩是:%f\n", stu.name, stu.age, stu.score);
}
int main(int argc, const char * argv[]) {
struct Student stu;
stu.name = "beyhuang";
stu.age = 22;
stu.score = 88;
display(stu);
return 0;
}
再来看看 OC 中的类
#import <Foundation/Foundation.h>
//声明类Student
@interface Student : NSObject //通过@interface关键字来声明类
//类所包含的变量
@property NSString *name;
@property int age;
@property double score;
//类所包含的函数
-(void)display;
@end //使用@end关键字结束类的声明
//实现在类中声明的函数
@implementation Student //通过@implementation关键字来实现类中的函数
-(void)display{
NSLog(@"%@的年龄是 %d,成绩是 %f", self.name, self.age, self.score);
}
@end //使用@end关键字结束类中函数的实现
int main(int argc, const char * argv[]) {
//通过类来定义变量stu1,即创建对象stu1
Student *stu1 = [[Student alloc] init]; //alloc函数为对象分配内存空间,init函数会初始化对象
//操作类的成员
stu1.name = @"beyhuang";
stu1.age = 18;
stu1.score = 66.66666;
//调用类的函数
[stu1 display];
return 0;
}
OC 使用
@interface
来声明一个类;Student
是类的名称;student
后面的NSObject
表示当前类派生自NSObject
类在 OC 中,类所包含的变量和函数都有特定的称呼,变量被称为属性(Property),函数被称为方法(Method),属性和方法统称为类的成员(Member)。从上面的代码可以看出,声明类的属性要使用
@property
关键字,而声明类的方法不需要使用任何关键字。-
号和+
号代表的意思:减号表示
为实例方法,必须使用类的实例才可以调用的。
比如C语言中,一个方法的写法可能是:
void hello(bool ishello) { ...... }
用Objective-C写出来就是
-(void) hello:(BOOL)ishello { ...... }
加号表示类方法,这类方法是可以直接用类名来调用的,就是其他函数可以直接调用这个类中的这个函数,而不用创建这个类的实例。
消息表达式
// [obj msg]; [stu1 display];
上面就是消息表达式的语法,其中消息接受者 obj 是一个对象,消息 msg 告诉它要去做什么