IOS升级之 Objective-c新特性

采用现代objective - c

来源:http://www.cnblogs.com/chensheng12330/p/3950004.html

多年来,objective - c语言已经发展和演变。 虽然核心概念和实践保持不变,部分语言经历了重大的变化和改进。 这些现代化提高类型安全、内存管理、性能、和其他方面的objective - c,使你更容易编写正确的代码。 采用这些变化是很重要的在你的现有的和未来的代码来帮助它变得更加一致的,可读的,有弹性。

Xcode提供了一个工具来帮助使你的一些结构性变化。 但是在使用这个工具之前,你想了解什么改变它将提供您的代码,以及为什么。 本文强调了一些最重要的和有用的现代化采用你的代码库。

instancetype

使用 instancetype 关键字作为返回类型的方法,该方法返回类的实例,他们呼吁(或该类的子类)。 这些方法包括 分配 初始化 工厂方法和类。

使用 instancetype 而不是 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"
}

因为 instancetype 返回类型的 + factoryMethodA ,消息的类型的表达式 MyObject * 。 自 myObject 没有 数 方法,编译器将发出警告 线:

main.m: ’MyObject’ may not respond to ‘count’

然而,由于 id 返回类型在 + factoryMethodB ,编译器可以给没有警告 线。 因为类型的对象 id 可以是任何类,由于方法叫什么 数 存在在一些类,编译器可能的返回值 + factoryMethodB 实现方法。

以确保 instancetype 工厂方法的子类化行为,一定要使用 (自我类) 在分配类而不是直接引用的类名。 遵循这个惯例确保编译器将正确推断出子类类型。 例如,考虑这样做的一个子类 myObject 从前面的示例:

@interface MyObjectSubclass : MyObject
@end
 
void doSomethingElse() {
        NSString *aString = [MyObjectSubclass factoryMethodA];
}

编译器提供以下警告这段代码:

main.m: Incompatible pointer types initializing ’NSString *’ with an expression of type ’MyObjectSubclass *’

在这个例子中, + factoryMethodA 消息发送返回一个对象的类型 MyObjectSubclass ,这是接收的类型。 编译器确定适当的返回类型 + factoryMethodA 子类应该 MyObjectSubclass 超类的,而不是宣布工厂方法。

如何采用

在你的代码中,替换出现的 id 作为一个返回值 instancetype 在适当的地方。 这是通常的情况 初始化 方法和类的工厂方法。 即使编译器自动转换方法,首先“alloc,”“init”,或“新”,有一个返回类型 id 返回 instancetype ,它不会把其他方法。 objective - c约定是编写 instancetype 显式方法。

注意,你应该更换 id 与 instancetype 只返回值,而不是在你的代码。 不像 id instancetype 可以使用关键字只有方法声明的结果类型。

例如:

@interface MyObject
- (id)myFactoryMethod;
@end

应该成为:

@interface MyObject
- (instancetype)myFactoryMethod;
@end

或者,您可以使用现代objective - c变换器在Xcode自动进行此更改您的代码。 有关更多信息,请参见 使用Xcode重构您的代码

属性

一个objective - cproperty是一个公共或私有方法声明

@property 语法。

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

属性获取一个对象的状态。 他们反映对象的本质属性和关系到其他对象。 属性提供一个安全、方便的方式与这些属性,而无需编写一组自定义访问器方法(虽然属性允许定制的getter和setter,如果需要的话)。

使用属性而不是实例变量在尽可能多的地方提供了许多好处:

  • Autosynthesized getter和setter。 当你声明一个属性,默认情况下为你创建getter和setter方法。
  • 更好的意图声明一组方法。 因为访问器方法的命名约定,很明显的getter和setter。
  • 属性关键字表示关于行为的额外信息。 属性提供潜在的声明的属性assign (vs copy), weakatomic (vs nonatomic),等等。

属性方法遵循一个简单的命名约定。property是属性的名称(例如, 日期 ), Setter 是属性的名字吗 集 前缀,写在驼峰式大小写(例如, 设置当前日期 )。 布尔属性的命名约定是声明他们叫getter开始这个词“是”:

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

因此,所有的以下工作:

if (color.blue) { }
if (color.isBlue) { }
if ([color isBlue]) { }

在决定什么可能是一个属性,记住,不是属性如下:

  • 初始化 方法
  • 复制 方法, mutableCopy 方法
  • 工厂方法类
  • 一种方法,并返回一个启动一个动作BOOL结果
  • 一种方法,明确内部状态变化getter的副作用

此外,考虑以下的规则集时识别潜在的属性在代码:

  • 一个读/写属性有两个访问器方法。 setter接受一个参数并返回什么,getter不接受参数并返回一个值。 如果你把这组方法转换成属性,标记它 读写 关键字。
  • 一个只读属性有一个访问器方法,getter,不接受参数并返回一个值。 如果你把这个方法转换成属性,标记它 只读的 关键字。
  • getter应 幂等 (如果一个getter两次,第二次调用导致相同的结果作为第一个)。 但是,它是可以接受的一个getter每次的计算结果。

如何采用

确定一组方法,有资格被转换成属性,诸如此类的:

- (NSColor *)backgroundColor;
- (void)setBackgroundColor:(NSColor *)color;

并使用声明它们 @property 语法与适当的关键字:

@property (copy) NSColor *backgroundColor;

房地产信息关键字和其他考虑,明白了 封装数据

或者,您可以使用现代objective - c变换器在Xcode自动进行此更改您的代码。 有关更多信息,请参见 使用Xcode重构您的代码

枚举宏

的 NS_ENUM 和 NS_OPTIONS 宏提供一个简洁、简单的定义枚举的方法和基于c语言的选项。 这些宏提高代码完成在Xcode和显式地指定枚举类型和大小的和选项。 此外,这种语法声明枚举的方式由年长的编译器,正确评估和更新那些可以解释潜在的类型信息。

使用 NS_ENUM 宏定义 枚举 一组互斥的值:

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
        UITableViewCellStyleDefault,
        UITableViewCellStyleValue1,
        UITableViewCellStyleValue2,
        UITableViewCellStyleSubtitle
};

的 NS_ENUM 宏可以帮助定义枚举的名称和类型,在这种情况下 UITableViewCellStyle 类型的 NSInteger 。 为枚举类型 NSInteger 

使用 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
};

像枚举, NS_OPTIONS 宏定义一个名称和一个类型。 然而,通常应该选择的类型 NSUInteger 

如何采用

取代你 枚举 这样一个声明:

enum {
        UITableViewCellStyleDefault,
        UITableViewCellStyleValue1,
        UITableViewCellStyleValue2,
        UITableViewCellStyleSubtitle
};
typedef NSInteger UITableViewCellStyle;

与 NS_ENUM 语法:

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
        UITableViewCellStyleDefault,
        UITableViewCellStyleValue1,
        UITableViewCellStyleValue2,
        UITableViewCellStyleSubtitle
};

但是当你使用 枚举 定义一个位掩码,例如:

enum {
        UIViewAutoresizingNone                 = 0,
        UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
        UIViewAutoresizingFlexibleWidth        = 1 << 1,
        UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
        UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
        UIViewAutoresizingFlexibleHeight       = 1 << 4,
        UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
typedef NSUInteger UIViewAutoresizing;

使用 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
};

或者,您可以使用现代objective - c变换器在Xcode自动进行此更改您的代码。 有关更多信息,请参见 使用Xcode重构您的代码

对象初始化

在objective - c中,对象初始化是基于的概念 指定的初始化程序 一个初始化方法,负责调用它的一个超类的初始化,然后初始化自己的实例变量。 没有指定初始值设定项被称为初始化 方便的初始化 。 连锁便利初始化通常委托给另一个initializer-eventually终止在指定initializer-rather不是自己执行初始化。

指定的初始化程序模式有助于确保继承初始化正确初始化实例变量。 子类需要执行重要的初始化应该覆盖其超类的所有指定的初始化,但它不需要覆盖方便初始化。 关于初始值设定项的更多信息,请参阅 对象初始化

明确指定的区别和指定的初始化程序清晰,你可以添加 NS_DESIGNATED_INITIALIZER 宏观的任何方法 初始化 家人,表示它指定初始值设定项。 使用这个宏介绍一些限制:

  • 指定的初始化器的实现必须连锁超类 初始化 方法( (超级init……) )这是一个超类初始化器指定。
  • 方便的实现初始化器(初始化器不标记为一个指定的初始化器内至少有一个初始化的类标记为一个指定的初始化器)必须委托给另一个初始化器(带 (自我init……))。
  • 如果一个类提供了一个或多个指定的初始化程序,它必须实现所有的指定初始化它的超类。

如果违反了这些限制,你收到来自编译器的警告。

如果您使用 NS_DESIGNATED_INITIALIZER 宏在你类,你需要马克你所有的指定初始化这个宏。 所有其他初始化被认为是便利的初始化。

如何采用

确定指定的类初始化器,和标记的 NS_DESIGNATED_INITIALIZER 宏。 例如:

- (instancetype)init NS_DESIGNATED_INITIALIZER;

自动引用计数(ARC)

自动引用计数(ARC)是一个编译器特性,它提供了自动objective - c对象的内存管理。 而不是你的记得使用 保留 释放 autorelease 一生,ARC评估需求的对象和自动插入适当的内存管理要求你在编译时间。 编译器也会产生适当的 dealloc 你的方法。

如何采用

Xcode提供了一个工具,自动化ARC转换的机械部件(如删除 保留 和 释放 调用),并且帮助你解决问题,移居者不能自动处理。

使用Xcode重构您的代码

Xcode提供了一个现代objective - c变换器,可以帮助你在现代化过程中。 虽然转换器有助于识别和潜在应用现代化的机制,它不解释代码的语义。 例如,它不会检测到你 切换 方法是一种行动,影响你的对象的状态,并将错误地提供现代化这一行动是一个属性。 确保手动审查和确认任何更改转换器提供使您的代码。

前面描述的现代化,转换器提供了:
  • 改变 id 来 instancetype 在适当的地方
  • 改变 枚举 来 NS_ENUM 或 NS_OPTIONS
  • 更新 @property 语法
除了这些现代化,这个转换器推荐额外的代码变更,包括:
  • 转换成文字,所以这样的声明 [NSNumber numberWithInt:3)简写为:@3 
  • 使用加下标,所以这样的声明 [dictionary setObject:@3 forKey:key]

使用现代objective - c变换器,在Xcode里操作路径 Edit > Refactor > Convert to Modern Objective-C Syntax。

时间: 2024-10-12 22:21:52

IOS升级之 Objective-c新特性的相关文章

最新iOS 6 in Xcode4.5新特性——Storyboard和属性自动绑定

最新iOS 6 in Xcode4.5新特性编程之二(上)——Storyboard和属性自动绑定 从Xcode 4.3开始,Storyboard 就是iOS 5和iOS 6中令人兴奋的一个新特性,他将为你在创建用户界面上节省很多时间. 那么究竟什么是Storyboard呢?我将用一幅图片来向你展示: 下面这个就是本实例中即将用到的Storyboard. 关于故事板编程,我在“最新Xcode 4.3.2 下使用Storyboard和ARC开发iPhone4程序 03——Storyboard类及使用

iOS开发实用技巧—项目新特性页面的处理

iOS开发实用技巧篇—项目新特性页面的处理 说明:本文主要说明在项目开发中会涉及到的最最简单的新特性界面(实用UIScrollView展示多张图片的轮播)的处理. 代码示例: 新建一个专门的处理新特性界面的控制器,可以实用代码也可以用xib,在这里实用纯代码方式,创建一个控制器NewfeatureViewController. 头文件代码: 1 // 2 // JMNewfeatureViewController.h 3 // 4 5 #import <UIKit/UIKit.h> 6 7 t

iOS之Xcode8 Auto Layout新特性

目录 1.Incrementally Adopting Auto Layout 2.Design and Runtime Constraints 3.NSGridView 4.Layout Feedback Loop Debugging 一.Incrementally Adopting Auto Layout Incrementally Adopting Auto Layout是什么意思呢?在我们IB里面布局我们的View的时候,我们并不需要一次性就添加好所有的constraints.我们可以一

java1.4升级到java1.5 新特性

前几天和一位腾讯的技术大牛聊天,聊到关于jdk的很多支持,包括jvm的优化,gc的调用机制,1.4-到1.8每次升级版本的新特性等,做软件这行这么多年了,一直在使用java,但是却从来没有细细的研究每个版本新特性到底有什么不同,所以特意编写了这么一篇文档,让自己能了解些他们的新特性,也共享一下新特性的改变,当然我下面的验证并不能当做最官方的,但最起码我是一个一个实验了,如果存在问题或解释的不正确的,也劳烦各位大牛给予指正. 目前我下载的jdk版本,如果大家需要这些版本的话,后期我会上传到百度云上

MQTT 3.1.1,值得升级的6个新特性

前言 以前看英文文章或资料,看完之后,摘要或者忘记.这一次选择感兴趣的MQTT 3.1.1介绍文章资料,引文见文末,作为练手:非完全翻译,去除掉一些广告性描述,若侵权,请告知. 在沉寂了四年之后,QTT 3.1.1规范于2014年10月30号正式发布,与此同时MQTT 3.1.1已成为OASIS(结构化信息标准促进组织)开放物联网消息传递协议标准(连接1 连接2),换种说法就是MQTT 3.1.1已升级为国际物联网标准. 正如HTTP为人们通过万维网分享信息铺平了道路一样,MQTT能将几十亿低成

iOS 11系列 - Xcode 9新特性

Xcode 9最近刚刚发布,带来了一系列不错的新特性,可以更好的帮助到开发者完成开发工作. Xcode Runtime Tool Xcode 9中有许多Runtime Tool可以帮助开发者找到代码错误,包括如下: Main Thread Checker  -  Xcode 9新引入 Address Sanitizer Thread Sanitizer Undefined Behavior Sanitizer Using Runtime Tools Effectively Main Thread

iOS开发——swift篇&amp;Swift新特性(一)语言基础

语言基础中的新特性 常量和变量的命名 Swift可以使用几乎任何字符来作为常量和变量名,包括Unicode: let π = 3.14159 let 你好 = "你好世界" let 星星 = "★" 注释可嵌套 Swift中的多行注释/**/可以嵌套,这样可以方便地在大段已注释的代码块中继续添加注释: /* this is the start of the first multiline comment /* this is the second, nested m

最新iOS 6 in Xcode4.5新特性编程之一——自动布局(1)

随着iOS 6正式版和OS X 10.8.2正式版发布之后,苹果还向开发者发布了其应用开发工具Xcode最新版,在最新的Xcode 4.5版本中增加了: 自动布局对OS X和iOS的支持; 同时也增强了对MacBook Pro的Retina显示屏支持; 及对Objective-C的一些优化.下面来研讨一下自动布局对OS X和iOS的支持!! 通常来说,如果屏幕是固定尺寸,那么设计它的用户界面不会很难,但如果屏幕的frame需要能够变化,那么其中各个UI元素的位置以及尺寸也必须为了适应新的尺寸做相

iOS开发——swift篇&amp;Swift新特性(二)函数、枚举、类与结构

函数.枚举.类与结构 可变参数 Swift的函数可以接受零个或多个指定类型的参数值,使用...来表示传递的是可变参数 func arithmeticMean(numbers: Double...) -> Double { var total: Double = 0 for number in numbers { total += number } return total / Double(numbers.count) } arithmeticMean(1, 2, 3, 4, 5) // ret

iOS开发——swift篇&amp;Swift新特性(三)属性、方法、下标

属性.方法.下标 存储属性和计算属性 类.结构和枚举都能够定义存储属性和计算属性.其中存储属性就是常见的形式,又分为变量属性和常量属性,如: struct Point { var x = 0.0, y = 0.0 } struct Size { var width = 0.0, height = 0.0 } 计算属性本身不是一个值,但是它提供getter和setter来间接地使用和设置存储属性的值: struct Rect { var origin = Point() var size = Si