標籤:style blog io ar color os 使用 sp for
Fun with instance variables執行個體變數的樂趣 Take a look at MasterViewController.h:——看看 MasterViewController類
@interface MasterViewController : UIViewController <UITableViewDataSource, UITableViewDelegate,DetailViewControllerDelegate> {// Instance variables for outletsUITableView *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 variablesNSDictionary *namesDictionary; NSMutableDictionary *valuesDictionary; NSArray *sortedSectionNames;// For the "sorted by value" screenBOOL 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" screenBOOL 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!elsesegmentedControl.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;elseself.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之後都可以編譯通過這個特性。
備忘:這是我實驗翻譯的一些東西,但是我覺得翻譯更多的是學習,所以我決定翻譯相對近點出的書吧,不可否認,我翻譯的還是比較糟糕的,但是慢慢來吧!
加油,親愛的自己!
iOS 6 By Tutorials ---第二章--【第二彈】--【翻譯】