博看|现代Objective-C语法

Posted 博看文思

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了博看|现代Objective-C语法相关的知识,希望对你有一定的参考价值。


博看|现代Objective-C语法


这些年来 Objective-C 得到了长远发展. 尽管那些核心概念还和以前一样,但是其内部已经有了质的改变. Modern Objective-C 提高了类型安全,内存管理,性能等方面,使得代码比之前更易读写.不仅如此,采用Modern Objective-C 也能使你现在和将来的代码带来更加一致.

Xcode 提供了一些工具帮你适应 Modern Objective-C ,不过在你使用这些工具之前,最好还是了解一下其原理.

instacetype

使用 instancetype 关键字作为 alloc , init 方法的返回值类型代替 id,用以提高Objective-C 的类型安全.

举个栗子:


@interface MyObject : NSObject

+ (instancetype)factoryMethodA;

+ (id)factoryMethodB;

@end

@implementation MyObject

+ (instancetype)factoryMethodA { return [[[self class] alloc] init]; }

+ (id)factoryMethodB { return [[[self class] alloc] init]; }

@end

void doSomething() {

NSUInteger x, y;

x = [[MyObject factoryMethodA] count]; // Return type of +factoryMethodA is taken to be "MyObject *"

y = [[MyObject factoryMethodB] count]; // Return type of +factoryMethodB is "id"

}

+factoryMethonA 的返回值类型为 instancetype ,效果等同于MyObject * ,因此在 Myobject 类中没有声明 count 方法之前,x 那一行,编译器会给出如下警告.

main.m: MyObjectmay not respond to count

+factoryMehtonB 的返回值类型为 id , 效果等同于 void * ,可以被指向任意类型, 因此在 y 那一行不会给出任何警告.

为了确保使用 instancetype 作为返回值的工厂方法的的类的子类能够拥有正确的行为,应该尽量使用 [self class] 而不是直接通过类的名称直接引用 (译者注 : NSClassFromString(@"ClassA");) , 遵循这个规则可以确保编译器推断出正确的子类类型.


博看|现代Objective-C语法

举个栗子:

@interface MyObjectSubclass : MyObject

@end

void doSomethingElse() {

NSString *aString = [MyObjectSubclass factoryMethodA];

}

编译器给出如下警告

main.m: Incompatible pointer types initializing

NSString *with an expression of type MyObjectSubclass *

(跟我读, Incompatible pointer types of type MyObjectSubclass ) 编译器根据调用者推断出返回这类型应该为 MyObjectSubclass,而不是父类类型 MyObjectClass

How to Adopt

在代码的合适位置,id 替换为 instancetype . 比如 init alloc 工厂方法 以及一些以 alloc init new 开头的,返回值为 id 的方法

Note: 你只需要将返回值类型替换 id instancetype ,而且 instancetype 只能被用作返回值类型.


博看|现代Objective-C语法

举个栗子:

转变前

@interface MyObject

- (id)myFactoryMethod;

@end

转变后

@interface MyObject

- (instancetype)myFactoryMethod;

@end

Porperties

Objective-C property 的访问权限通过 @property 指定

@property (readonly, getter=isBlue) BOOL blue;

Property 将对象的状态生成快照,把对象的真实属性反射到其他对象中. Property 提供了安全,便利的方法与真实的属性进行交互,而不需要手动实现 setter,getter

使用属性替代示例变量能够带来如下益处:

** 自动合成 setter , getter. ** 属性一旦声明,就拥有了 setter getter 方法

** 有意义的方法名称. ** 访问器的名称非常便利,清晰的反映出了getter,setter 的任务

** 表达额外的信息和行为. ** 属性提供了额外的声明属性,比如 assign copy weak atomic nonatomic

Enumeration Macros

NS_ENUM NS_OPTIONS 宏提供基于 C 语言的 简洁的枚举定义方式,并且可以指定其枚举类型和大小.此外,这些宏也是版本兼容的.

使用 NS_ENUM 定义枚举:

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {

UITableViewCellStyleDefault,

UITableViewCellStyleValue1,

UITableViewCellStyleValue2,

UITableViewCellStyleSubtitle

};

上述代码中, NS_ENUM 同时定义了枚举的名称和类型

使用 NS_OPTIONS 定义基于位移的枚举值

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

};

How To Adopt

替换 enum NS_ENUM

enum {

UITableViewCellStyleDefault,

UITableViewCellStyleValue1,

UITableViewCellStyleValue2,

UITableViewCellStyleSubtitle

};

typedef NSInteger UITableViewCellStyle;

-

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {

UITableViewCellStyleDefault,

UITableViewCellStyleValue1,

UITableViewCellStyleValue2,

UITableViewCellStyleSubtitle

};

替换 按位 enum NS_OPTIONS

enum {

UIViewAutoresizingNone = 0,

UIViewAutoresizingFlexibleLeftMargin = 1 << 0,

UIViewAutoresizingFlexibleWidth = 1 << 1,

UIViewAutoresizingFlexibleRightMargin = 1 << 2,

UIViewAutoresizingFlexibleTopMargin = 1 << 3,

UIViewAutoresizingFlexibleHeight = 1 << 4,

UIViewAutoresizingFlexibleBottomMargin = 1 << 5

};

typedef NSUInteger UIViewAutoresizing;

-

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

};

Automatic Reference Counting (ARC)

自动引用计数是编译器的特性,可以自动化Objective-C 对象的内存管理.用于替代你所知道的retain release autorelease ,ARC 会对对象的生命周期进行评估,编译时自动在适当的位置插入合适的 retain release autorelease 等关键字,并且也会生成合适的 dealloc 方法。



How To Adopt

Xcode 提供了ARC 的转换工具,更多信息请查阅 Transitioning to ARC Release Notes

Refactoring You Code Using Xcode

Xcode 提供了 Modern Objective-C 的转化器帮你完成现代化,但有时也无能为力.因此,你必须审核转后的代码,并做一些手动的修改

在之前的描述中,转化器提供了如下功能:

在适当的位置将 id 转为 instancetype

enum 转为 NS_ENUM NS_OPTIONS

更新 @property 语法

此外,转化器也推荐你做出一些额外的改变:

转为字面量,

例如 [NSNumber numberWithInt:3] ==> @3

使用角标,

例如 [dictionary setObject:@3 forKey:key] ==> dictionary[key]=@3

Xcode , Edit > Refactor > Convert to Modern Objective-C Syntax.

即可完成转化。




以上是关于博看|现代Objective-C语法的主要内容,如果未能解决你的问题,请参考以下文章

采用现代Objective-C

在 Objective-C 中实现纯虚方法

Objective-C Block与函数指针比较

从Objective-C向Swift转换学习到的经验

带有延迟 NSMenu 的 NSButton - Objective-C/Cocoa

如何/在哪里声明用于编写objective-c代码的接口、实现、程序格式中的实例变量?