基本语法

基本类型

布尔型

布尔型主要有两种使用方式:

1
2
3
BOOL v1 = YES;		// 常用的布尔型使用方式,两个取值分别是 YES, NO

bool v2 = false;	// 两个取值分别是 true, false

上面的两种方式不是等价的,前者是通过下面的方式实现的:

1
2
3
4
5
6
7
#if (TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH
	#define OBJC_BOOL_IS_BOOL 1
	typedef bool BOOL;
#else
	#define OBJC_BOOL_IS_CHAR 1
	typedef unsigned char BOOL;
#endif

整数型

除了 C 中实现的整数和无符号整数,OC 同样也实现了两个整数类型:

1
2
3
4
5
NSInteger v1 = 8;

NSUInteger v2 = 9;

// 无符号和有符号都是:32 位类型为 int, 64 位类型为 long

同样也可以看看他们的实现方式:

1
2
3
4
5
6
7
#if __LP64__ || 0 || NS_BUILD_32_LIKE_64
	typedef long NSInteger;
	typedef unsigned long NSUInteger;
#else
	typedef int NSInteger;
	typedef unsigned int NSUInteger;
#endif

数字封装

Objective-C 对数字进行了一个类的封装 NSNumber

  • 在 c/c++ 中,当需要使用数字的时候,我们通常使用简单数据类型,如:intlongfloat
  • 然而,在实际开发过程中,我们经常会遇到需要使用对象的场景。所以 Objective-C 中提供了NSNumber 类用来包装简单数字类型。

它封装了一些比较有用的创建方法,下面是一些例子:

1
2
3
4
5
6
NSNumber *num1 = [NSNumber numberWithShort:1];
NSNumber *num2 = [NSNumber numberWithInt:2];
NSNumber *num3 = [NSNumber numberWithLong:3];
NSNumber *num4 = [NSNumber numberWithFloat:4];
NSNumber *num5 = [NSNumber numberWithBool:YES];
NSNumber *num6 = [NSNumber numberWithInteger:5];

重载了 @ 符号进行赋值(语法糖):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
NSNumber *num1 = @1;
NSNumber *num2 = @INT_MAX;
NSNumber *num3 = @LONG_MAX;
NSNumber *num4 = @4.0f;
NSNumber *num5 = @YES;
NSNumber *num6 = @NSIntegerMax;

int a = 1;
NSNumber *num7 = @(a);
NSNumber *num8 = @(1 + 2);

PostScript

  • NSNumber 这个类不能进行数值运算。

字符串

Objective-C 作为同样也是支持 C 中的字符串定义语法(单引号指定单个字符,双引号指定字符串),然而大部分 Objective-C 程序是使用一个字符串类的封装:

1
2
3
4
5
NSString *myString1 = @"Hello World";
NSString *myString2 = [NSString stringWithFormat:@"%d %s", 1, @"String"];

// convert from a c-style string
NSString *fromCString = [NSString stringWithCString:"A C string" encoding:NSASCIIStringEncoding];

可以看到声名一个字面量的字符串类型要做的事情,只是在字符串之前加上一个 @ 符号。

枚举类型

参考资料:https://www.jianshu.com/p/994dc9f4958d

在传统的 c 枚举类型中,使用 typedef 可以使枚举变量的声明更加简单:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
typedef enum {
    FlyStateOne, FlyStateTwo, FlyStateThree
}state;

// 它与下面的这种声明方式是等价的
enum FlyTypeState{
    FlyTypeOne, FlyTypeTwo, FlyTypeThree
};
FlyState state
typedef enum  FlyTypeState state;

c++11 标准中对枚举类型标准进行了扩充,可以指明枚举的底层数据类型。比如:

1
2
3
enum FlyState:NSInteger{ //设置底层数据类型为NSInteger
    FlyStateOne, FlyStateTwo, FlyStateThree
};

问题是这种标准并不支持使用上面描述的 typedef 语法。

Objective-C 最常用的枚举数据类型 NS_ENUMNS_OPTION 为了解决这个问题诞生:

  1. NS_ENUM 是一个宏,是对 c++ 中的枚举类型的上层封装。比如下面的一个 NS_ENUM 使用实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
        UIViewAnimationTransitionNone,
        UIViewAnimationTransitionFlipFromLeft,
        UIViewAnimationTransitionFlipFromRight,
        UIViewAnimationTransitionCurlUp,
        UIViewAnimationTransitionCurlDown,
    };
    
    UIViewAnimationTransition trans = UIViewAnimationTransitionNone;
    

    如果编译器支持新标准枚举则上面的定义,展开之后形成下面的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    typedef enum UIViewAnimationTransition:NSInteger UIViewAnimationTransition;
    
    enum UIViewAnimationTransition: NSInteger{
        UIViewAnimationTransitionNone,
        UIViewAnimationTransitionFlipFromLeft,
        UIViewAnimationTransitionFlipFromRight,
        UIViewAnimationTransitionCurlUp,
        UIViewAnimationTransitionCurlDown,
    };
    

    如果编译器不支持这种语法,那么这种声明与最开始列举的 typedef 是一样的。

  2. NS_OPTIONS 也是一个枚举类型,它可以用于将特征存储在整数的不同比特位上。比如下面这个:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
        UIViewAutoresizingNone                 = 0,
        UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
        UIViewAutoresizingFlexibleWidth        = 1 << 1,
        UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
        UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
        UIViewAutoresizingFlexibleHeight       = 1 << 4,
        UIViewAutoresizingFlexibleBottomMargin = 1 << 5
    };
    
    NSUInteger resize = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    

PostScript:

  • Objective-C 2.0 中,提供了 for-in 循环遍历枚举类型,称为快速枚举。

其他基本数据类型

其他数据类型基本与 c 中的语法一样。比如:

1
2
3
4
float var3 = 3.0f;//单精度浮点数
double var4 = 4.0;//双精度浮点数
long long var5 = 5;//64位整数
char var6 = 'a';//单个字符

类相关数据类型

在引入类的概念的时候,不同于 c++ 的一些特殊的类型:

  1. instancetype:是 clang 关键字,使方法返回所在类的类型,只能用作方法返回类型。
  2. id:指代任何位置类型的 NSObject 对象,类似于 void*
  3. nil:表示指向的对象指针为空,类似于 c++ 中的 nullptr

控制流

循环、条件跳转,都与 c 中的相同。

消息传递

Objective-C 里,与其说对象互相调用方法,不如说对象之间互相传递消息更为精确。此二种风格的主要差异在于 调用方法/消息传递 这个动作:

  • C++ 里类别与方法的关系严格清楚,一个方法必定属于一个类别,而且在编译时(compile time)就已经紧密绑定,不可能调用一个不存在类别里的方法。
  • 但在Objective-C,类别与消息的关系比较松散,调用方法视为对对象发送消息,所有方法都被视为对消息的回应。所有消息处理直到运行时(runtime)才会动态决定,并交由类别自行决定如何处理收到的消息。也就是说,一个类别不保证一定会回应收到的消息,如果类别收到了一个无法处理的消息,程序只会抛出异常,不会出错或崩溃。

比如 C++ 里,送一个消息给对象(或者说调用一个方法)的语法如下:

1
obj.method(argument);

Objective-C 中则写成:

1
[obj method: argument];

此二者并不仅仅是语法上的差异,还有基本行为上的不同。