iOS 6 By Tutorials ---第二章--【第二弹】--【翻译】

Fun with instance variables

实例变量的乐趣

Take a look at MasterViewController.h:——看看 MasterViewController类

@interface MasterViewController : UIViewController <UITableViewDataSource, UITableViewDelegate,

DetailViewControllerDelegate> {

// Instance variables for outlets

UITableView *tableView; UISegmentedControl *segmentedControl;

... }

@property (nonatomic, strong) IBOutlet UITableView *tableView; @property (nonatomic, strong) IBOutlet UISegmentedControl

*segmentedControl;

...

@end

Usually when you declare a property, you want to have it “backed” by an instance variable that stores the actual value for that property. For example, self.tableView (the property) actually reads and writes the value from the tableView instance variable.

一般你声明一个属性,你想让一个实例变量存储这个属性实际的值。例如:self.tableView(属性)实际上它的读写是通过tableView这个实例变量。

In the @interface above, you can see that the author has declared both the property and its backing instance variable. The instance variable sits inside the { } section, the property on its own line below that. (Sometimes you will see the IBOutlet specifier on the instance variable instead of the property. It doesn’t really matter where it goes.)

在上面的声明中,作者同时声明了属性和它支持的实例变量。实例变量声明在{}部分,属性在它之外。(有时会看到IBOutlet这个关键字修饰实例变量而不是属性,这并不重要)

When you do this, you’re essentially writing the same thing twice. Here’s the thing: this hasn’t been necessary for ages! The explicit declaration of the instance variable was only necessary for the iPhone 2.x Simulator because it used an older version of the Objective-C runtime. Quite some time ago now, the Simulator switched to the “modern” runtime, which is also what the actual iPhone uses, and this workaround became unnecessary.

当你这么做的时候,你基本上就是同上的事情写了两次。事情是这样的:这没必要。显示声明实例变量只有在iPhone 2.x模拟器的时候是必要的,因为它使用的是旧版的OC运行时。很久之前,模拟器已经切换到 了“现代的”运行时,那也是iPhone真机在使用的,所以这种解决方案是不必要的。

When you @synthesize a property, the compiler automatically creates that instance variable for you. That’s what @synthesize is for, after all. So there is no need to type the same thing again.

当你synthesize一个属性,编译器会自动创建一个与之相关的实例变量。毕竟那才是synthesize要做的。所以同样的事情没必要再做一次。

Note: In some older versions of Xcode, it used to be that if you allowed the compiler to auto-create instance variables, you couldn’t see the instance variables in the debugger. Happily, this is no longer the case, and you can now see the instance variables in the debugger as expected. So feel free to auto- generate!

注意:在一些老版本的Xcode中,如果你允许编译器自动创建实例变量,你在调试器中看不到这个实例变量。幸运的是,现在已经不是这样,你可以在调试器重看到这个你期望的实例变量。所以,感受自由生成实例变量吧!

So, go ahead and remove these two instance variable declarations from MasterViewController.h, and everything should work as before.

所以,从MasterViewController.h类中删除这两个实例变量,所有的还是会照常工作。

Also go ahead and remove all the instance variable declarations from DetailViewController.h. Same story. Each of those instance variables just exists for the sake of the property with the same name. Get rid of ‘em.

同样将DetailViewController.h类中的实例变量删除。每一个实例变量的存在只是为了跟属性有相同的名字。摆脱他们。

The new, simplified @interface section from DetailViewController.h should look like this:

简化之后的DetailViewController.h类看起来是这样的:

@interface DetailViewController : UIViewController

@property (nonatomic, strong) IBOutlet UINavigationBar *navigationBar;

@property (nonatomic, strong) IBOutlet UITextField *textField; 

@property (nonatomic, weak) id <DetailViewControllerDelegate>

delegate; 

@property (nonatomic, copy) NSString * sectionName;

@property (nonatomic, assign) NSUInteger indexInSection;

@property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSNumber *value;

- (IBAction)cancel:(id)sender; - (IBAction)done:(id)sender;

@end

Build and run, and everything should work just as before!

编译运行,所有都是与之前一样的。

But wait, there’s more...

但是,等等,还有更多。。。

You’re not done with the instance variables just yet. Currently the @interface of MasterViewController.h still declares several instance variables:

你不是完成了实例变量。目前在MasterViewController.h类中仍然声明了几个实例变量:

@interface MasterViewController : UIViewController <. . .> {

// Private instance variables

NSDictionary *namesDictionary; NSMutableDictionary *valuesDictionary; NSArray *sortedSectionNames;

// For the "sorted by value" screen

BOOL sortedByName; NSArray *sortedNames; NSArray *sortedValues;

}

As the comment indicates, these are “private” instance variables. They are used internally by this view controller only, and are not supposed to be accessed by any objects outside this class. (Sometimes developers put a @private declaration in there as well.)

评论指出,这些是私有变量。他们只是被这个控制器内部使用,这个类之外的任何对象都不能调用这些实例变量。(有时开发者会用@private修饰)

Wouldn’t it be better if outside objects didn’t know anything about these instance variables at all? In other words, why do they need to be exposed in the @interface section in the header file? There are good historical reasons why that was necessary, once upon a time – Objective-C having been built on top of the C language, to name one – but as of Xcode 4.2, the compiler no longer requires this. It is now possible to place instance variable declarations inside your implementation (.m) files instead.

如果外部对象不知道这些实例变量是不是会更好?换句话说,为什么他们需要在头文件中暴漏在@interface?这是有历史因素的,曾经,OC是建立在C语言上的,Xcode4.2之后,编译器不再需要这个。现在可以在.m文件中声明实例变量。

Cut the instance variable section out of the header file and paste it directly below the @implementation line in MasterViewController.m.

将实例变量的代码剪切到.m文件中

The @interface section in MasterViewController.h should now look like this:

MasterViewController.h文件看起来就是这样:

@interface MasterViewController : UIViewController <. . .>
@property (nonatomic, strong) IBOutlet UITableView *tableView; @property (nonatomic, strong) IBOutlet UISegmentedControl *segmentedControl;
- (IBAction)sortChanged:(UISegmentedControl *)sender;
@end

While the @implementation section in MasterViewController.m should now look like this:

MasterViewController.m文件看起来就是这样:

@implementation MasterViewController {

NSDictionary *namesDictionary; NSMutableDictionary *valuesDictionary; NSArray *sortedSectionNames;

// For the "sorted by value" screen

BOOL sortedByName; NSArray *sortedNames; NSArray *sortedValues;

}

That is a lot cleaner! Instance variables are typically only necessary inside the .m file, so that’s where they belong.

这是一个很大的清洁。实例变量只在他们应该在的.m文件中。

Note: You may wonder why some instance variables in this app have properties, and some do not. This is mostly a matter of style – some people like to create properties for everything, and some people don’t like to create properties at all. I only tend to create properties for things that must be accessible from outside a class, and for IBOutlets.

注意:你可能知道为什么这个应用中一些实例变量需要属性,一些不需要。这主要是一种风格—有的人喜欢把所有的都创建为属性,有的人根本不喜欢创建属性。我只有在外部确实会用到某个对象时才创建为属性或者是IBOutlets。

To synthesize, or not to synthesize

Countless books and tutorials have probably drilled this rule into you: if you have a @property you need to @synthesize it, at least if you want it to be backed by an instance variable. It is also possible to create your own getter and setter methods or to use @dynamic properties, but most of the time you use @synthesize.

大多数的书籍和教程可能告诉你这样一个规则:如果你定义了属性,如果你想得到一个实例变量的支持,你需要用 @synthesize修饰它。你也可以使用 @dynamic方法,自己写setter和getter方法,但实际上你会使用@synthesize。

Well, thanks to the automatic synthesize feature in Xcode 4.5, you don’t have to bother writing @synthesize statements anymore! The compiler will notice your @property statement and automatically synthesize the property and create the backing instance variable for you. Nice, eh?

当然,因为在Xcode4.5出现了新特性,可以不用再使用@synthesize语句了。编译器会自动创建这个属性对应的实例变量以及它的getter和setter方法。

Try this out by removing the @synthesize statements from AppDelegate.m, MasterViewController.m and DetailViewController.m. That shaves about nine or ten lines from the source code. Now build the app.

试试删除AppDelegate.m,MasterViewController.m 和 DetailViewController.m.中的@synthesize句子。那样会删掉九行或十行代码,编译一下项目。

Whoops, the compiler isn’t happy! It gives a number of errors in the code for MasterViewController.m, in this method:

哎呦,编译器不顺利!在MasterViewController.m文件中出现好多错误,在这个方法中:

- (void)viewDidLoad {

[super viewDidLoad];

if (sortedByName)
segmentedControl.selectedSegmentIndex = 0; // error!

else

segmentedControl.selectedSegmentIndex = 1; // error!

[self updateTableContents];

}

The offending lines are the ones that refer to segmentedControl. This used to work before you removed @synthesize, so what’s the big deal?

出现错误的是segmentedControl,在删除@synthesize之前是可以正常运行的,所以现在有什么大不了的?

As it turns out, this is an example of programmer sloppiness. If you declare a property for something, then best practice says you should always refer to it as self.property and not directly through its backing instance variable. Using self.property invokes the proper getter and setter methods, but direct access through the backing instance variable skips those. That may cause issues if your getter or setter does anything special, beyond changing the backing variable.

事实证明,这是一个马虎的程序员的例子。如果你声明了一些东西。使用它的地方最好是self. 而不是使用它的实例。用self. 会调用setter和getter方法,但是使用实例 就会跳过那些!如果你的getter或setter方法做了什么特殊的操作就会引起错误。

It’s best to always write self.property so you don’t have to worry about any of this. Here, however, the programmer forgot to use “self” and just wrote segmentedControl. The fix is to simply add self. to the references to segmentedControl, as follows:

最好使用self. ,这样在这方面你就不会出错。这里,就是程序员忘记使用self 只是写了segmentedControl。更正的方法就是简单的加上self.就可以,如下:

- (void)viewDidLoad {

[super viewDidLoad];

if (sortedByName) self.segmentedControl.selectedSegmentIndex = 0;

else
self.segmentedControl.selectedSegmentIndex = 1;

[self updateTableContents]; }

}

This still doesn’t answer the question of why this code compiled without problems before you removed @synthesize. That synthesize statement looked like this:

这仍然不能回答这段代码在删除@synthesize之前编译没有问题,synthesize修饰的语句看起来是这样子的:

@synthesize segmentedControl;

The statement above created a backing instance variable with the same name as the property: in this case, a variable also named segmentedControl. So before, you weren’t actually going through the property (self.segmentedControl) – you were accessing the instance variable directly (segmentedControl). This is an easy mistake to make, since the property and instance variable have the same name.

上面的语句创建了一个和属性同名的实例变量,在这种情况下,变量也名为segmentedControl。所以,你之前实际上不有走属性(self.segmentedControl)—而是你直接访问的实例变量(segmentedControl)。在属性和实例变量名字一样的时候,很容易犯这样的错误。

You may have seen a variation of the synthesize statement that looks like:

你可能会看到变量和 synthesize语句是这样的:

@synthesize segmentedControl = _segmentedControl;

The above notation allows you to specify a different name for the instance variable. This is a good practice, because it makes it harder to make the above mistake – you access the property with self.segmentedControl, and the instance variable with _segmentedControl.

上面的符号是允许你给实例变量指定不一样的名字。这是一个很好的做法,因为这样就不容易犯上面那样的错误—你使用属性通过self.segmentedControl,使用实例变量通过_segmentedControl。

Also, when you do this the compiler helps you out, just like you saw here. Since your program referenced segmentedControl without self, the compiler gave an error because that is neither a valid way to access a property nor the name of an existing variable. It should either be self.segmentedControl or _segmentedControl, not just segmentedControl.

同样,当你这样做的时候,编译器也会帮助你,就像你看到的那样。当编译器引用segmentedControl没有使用self,编译器就会报错,因为这既不是合法的途径访问属性也不是实例变量正确的名字。要使用self.segmentedControl 或 _segmentedControl,而不是segmentedControl。

By renaming the instance variable, you prevent the situation where you’re (mistakenly) using the backing instance variable directly, when you intended to use the property.

通过重命名实例变量,你可以防止当你要使用属性时却错误是使用了实例变量。

And that is exactly what auto-synthesize does: it creates a new backing instance variable named after the property, but prefixed with an underscore, just as if you had typed this:

这就是auto-synthesize做的:它创建了新的实例变量与属性对应,但是实例变量有下划线,格式如下:

@synthesize segmentedControl = _segmentedControl;

To verify this for yourself, change the offending lines to:

验证这些,可以将代码改为:

_segmentedControl.selectedSegmentIndex = . . .;

Now the code should compile successfully. Even though you never declared this variable anywhere yourself, it still exists because of auto-synthesize. (You probably should change it back to use the property before you continue, though.)

现在代码可以编译成功。尽管你在任何地方都没有声明过这个实例变量,它仍然是存在的,因为auto-synthesize。(尽管你可能会将它改回到使用属性之前)

Build and run, and everything should work as usual!

编译运行,所有的都是正常的。

Tip: Your apps don’t need to be iOS 6-only to take advantage of auto- synthesize. Apps compiled with this feature will still work all the way back to iOS 4. Nice!

建议:你的应用不用必须在iOS6下使用auto- synthesize。  应用在iOS4之后都可以编译通过这个特性。

备注:这是我实验翻译的一些东西,但是我觉得翻译更多的是学习,所以我决定翻译相对近点出的书吧,不可否认,我翻译的还是比较糟糕的,但是慢慢来吧!

加油,亲爱的自己!

时间: 2024-10-11 10:05:39

iOS 6 By Tutorials ---第二章--【第二弹】--【翻译】的相关文章

Git帮助文档阅读笔记----第二章-第二节

查看提交历史 1.查看提交历史 git log 默认不用任何参数的话,git log 会按提交时间列出所有的更新,最近的更新排在最上面 git log 有许多选项可以帮助你搜寻感兴趣的提交 1.  -p选项展开显示每次提交的内容差异 2.  -2显示最近的两次更新 该选项除了显示基本信息之外,还在附带了每次 commit 的变化.当进行代码审查,或者快速浏览某个搭档提交的 commit 的变化的时候,这个参数就非常有用了. 某些时候,单词层面的对比,比行层面的对比,更加容易观察.Git 提供了 

【软件构造】第二章第二节 软件构造的过程、系统和工具

第二章第二节 软件构造的过程.系统和工具 Outline 广义的软件构造过程 编程 静态代码分析 动态代码分析 调试与测试 重构 狭义的软件构造过程 构造系统:经典BUILD场景 构造系统的组件 构造过程和构造描述 Java编译工具 子目标和结构变体 构造工具 Notes ## 广义的软件构造过程 [编程(Coding)] 开发语言:如Java.C.Python 使用IDE(集成开发工具)的优势(组成) 方便编写代码和管理文件(有代码编辑器,代码重构工具.文件和库(Library)管理工具) 能

iOS 6 By Tutorials ---第一章--【第一弹】-【翻译】

iOS 6 By Tutorials(pdf 文档)  By the raywenderlich.com Tutorial Team 备注:本人没有怎么翻译过技术型的文章,慢慢翻之.---这本书总共是27章, Chapter 1:Introduction  --第一章:入门介绍 iOS 6 introduces an abundance of great new APIs and technologies that all iOS developers should learn – from A

第二章 第二个spring-boot程序

上一节的代码是spring-boot的入门程序,也是官方文档上的一个程序.这一节会引入spring-boot官方文档推荐的方式来开发代码,并引入我们在spring开发中service层等的调用. 1.代码结构如下 2.pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi

陶哲轩 实分析 第二章第二小节 习题解答

陶哲轩 实分析 第二小节 习题 最近从网上下载到了陶哲轩写的实分析,确实是本好书.不过所有的习题都没有给出答案.我试着自己做一遍习题,整理一份习题解答. 2.2.1 证明自然数加法是结合的 (a + b) + c = a + (b + c) 数学归纳法 a=0 时, 左边: (0+b)+c=b+c 右边: 0+(b+c)=b+c 左边 = 右边 假设当 a=n 时,(n+b)+c=n+(b+c) 成立 则,当 a=n++ 时 ((n++)+b)+c=((n+b)++)+c=((n+b)+c)++

第二章-第二题(每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令。比较项目的新旧版本的差别。)--by侯伟婷

第二题:每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令.比较项目的新旧版本的差别. 下面我将自己的练习结果和个人感受记录如下: 第一步:安装Git,设置自己的账号和邮箱,参见Git教程-廖雪峰的官方网站,网址如下参考资料1所示. 第二步:在Git中新建repository,名叫HelloWorld,并进行初始化,如图所示. 第三步:在HelloWorld版本库中新建了helloWorld.txt文件,用以练习G

第二章-第二题(练习使用git的add/commit/push/pull/fetch/clone等基本命令)--梁绍楠

题目描述: 每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令.比较项目的新旧版本的差别. 使用步骤: (1)创建版本库 选择一个合适的地方,创建一个空目录HelloWorld.而后通过git init把这个目录变成Git可以管理的仓库(目录下会多出了一个.git目录,该目录是git跟踪管理版本库的,勿轻易修改): 编辑hello文件,内容如下: (2)将文件hello放到git仓库 首先,需要设置用户名.邮箱信息

第二章——第二节 IPC机制的概述和使用

一.Serialiable与Paracle ①.作用    ②.使用 二.Binder与AIDL ①.各自的作用 三.如何使用IPC机制 四.IPC机制的原理 ①.流程图  ②.自己编译自动生成的Aidl代码 回答: Serialiable的使用 步骤:1.创建类并继承Serializable接口  2.将对象序列化到文件中 3.从文件中获取序列化的文件 详细步骤: 1.创建Book类,并继承Serializable,编写serialVersionUID降低反序列化失败的概率 public cl

C++Primer 第二章 第二部分

//1.一条声明语句由一个基本数据类型和紧随其后的一个声明符列表组成.每个声明符命名了一个变量并指定了该变量为与基本数据类型有关的某种类型.在同一条声明语句中,基本数据类型是相同的,但是声明符不一定相同. // 基本类型:是类型说明符,可用const修饰,在声明语句中位于声明符之前.基本类型提供了最常见的数据类型,以此基础构建声明符. // 声明符:是声明的一部分,包括被定义对象的名字和类型修饰符.其中类型修饰符(比如const,* ,&等)可有可无. int value0 = 0; //此定义

第二章-第二题(练习使用git的add/commit/push/pull/fetch/clone等基本命令)-By郭青云(未完待续)

题目描述: 每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令.比较项目的新旧版本的差别. 使用步骤: 未完待续...... 参考文件:http://blog.csdn.net/u012575819/article/details/50553501