It, optionally, performs two transitions on every source fi le in your project: Modernize Loops Convert instance variables to properties To update your entire project to Objective - C 2.
Trang 1Loop modernization only transforms while loops that meet these criteria:
The while loop iterates through the objects in a collection using an NSEnumerator object.
Uses the message [enumerator nextObject] to obtain each object
Starts with the fi rst object in the collection
Processes each object, in order, without skipping objects (this does not preclude exiting the loop early using a break statement)
The second and third points mean that you can ’ t use refactoring to modernize a loop that uses
- reverseObjectEnumerator
An often - overlooked feature of fast enumeration is that the modern NSEnumerator class also conforms to NSFastEnumeration The implication is that any enumerator object can be treated as the collection object in a fast enumeration statement Consider the following code:
NSEnumerator* e = [collection reverseObjectEnumerator];
for ( id obj in e ) {
}
The enumerator acts as a proxy for its collection The statement loops through the objects returned by the enumerator This is particularly useful with enumerators that return a subset of a collection or process objects in a different order, like - [NSDictionary keysSortedByValueUsingSelector:]
It should be noted that this trick does not improve the performance of your application; a fast enumeration using an enumerator object isn ’ t any faster than using the enumerator object directly In other words, you don ’ t get the “ fast ” part of fast enumeration; you just get the convenience of a concise syntax
UPDATING A PROJECT TO OBJECTIVE - C 2.0
The Edit ➪ Convert to Objective - C 2.0 command is specifi cally designed to ease that transition of legacy projects to Objective - C 2.0 It, optionally, performs two transitions on every source fi le in your project:
Modernize Loops Convert instance variables to properties
To update your entire project to Objective - C 2.0, follow these steps:
1. Choose the Edit ➪ Convert to Objective - C 2.0 command
2. Select either, or both, of the Modernize loops or Use properties transformations
The modernize loops transformation is the same one described in the previous section, just applied globally to every Objective - C source fi le in your project
➤
➤
➤
➤
➤
➤
Trang 2198 ❘CHAPTER 10 REFACTORING
The use properties transformation converts simple instance variables to Objective - C 2.0 properties
Is does this by
Adding a @property directive for each instance variable
Adding a @synthesize directive for each instance variable that does not already have KVC -compliant getter and setter methods with the same name
REFACTORING PITFALLS
As mentioned at the beginning of the chapter, any change to an application — no matter how
seemingly inconsequential — can occasionally have profound effects on its behavior Although the
refactoring logic is quite intelligent, it isn ’ t omniscient It makes mechanical replacements that are
reasonably expected to be functionally equivalent, but may not be
Many of these pitfalls can be avoided by refactoring your application defensively and with the
assumption that any transformation could introduce a bug Try to follow these best practices when
refactoring:
1. Your project should build successfully and function correctly before beginning any
refactoring
2. Make use of the refactoring preview; diligently review each proposed change before
com-mitting the transformation Disable any changes that aren ’ t appropriate
3. Always make a project snapshot They are easy to discard later
4. After the transformation, make sure the project still builds Fix any compilation errors that
appear
5. If you have any unit tests defi ned, run them
Each transformation carries some specifi c pitfalls The next few sections highlight common issues
that you ’ re likely to encounter when refactoring
Renaming a method only renames the occurrences of that method defi ned by a single class
If that method overrides an inherited method, the inherited method in the superclass is not
renamed If you need to rename an inherited method, you must rename the same method in all other classes
Conversely, renaming a method could change it from a unique method to one that now overrides a method in its superclass
Encapsulate only generates getter and setter methods It does not produce @property or
@synthesize directives If you ’ re using Objective - C 2.0, just write @property or
@synthesize directives instead of trying to use encapsulate
➤
➤
➤
➤
➤
Download at getcoolebook.com
Trang 3The getter and setter methods assume that you are using traditional managed memory, not garbage collection Though this will work in a garbage collection environment, it still generates more code than is optimal Again, @property or @synthesize directives are a better solution.
The @synthesize directive automatically adapts to your chosen memory management model
Existing memory management is overlooked, which can create over - retain and over - release issues For example, encapsulating the ivar variable will replace the two statements [ivar release]; ivar=nil; with the statements [[self ivar] release]; [self setIvar:nil]; This results in ivar being released twice: once in the code and again in the setter
The visibility of the original instance variable remains unchanged If it were @public before the transformation, it ’ s still public afterwards After the transformation, change the visibil-ity of the instance variable to @protected or @private
The setter method generated is not thread - safe
Moving an instance variable to its superclass does not migrate its @property or
@synthesize directives
The visibility of a variable is not retained A @private variable could become @protected
or @public
If you migrate related methods, you could migrate methods that now refer to properties defi ned only in the subclass This requires either migrating those other properties as well, or redesigning the methods
The refactoring tool warns you if the superclass already has a variable or method with the same name, but it won ’ t prevent you from applying the transformation The result will be a class with duplicate methods
You can only migrate a variable or method to its immediate superclass
Moving an instance variable to one of its subclasses does not migrate its @property or
@synthesize directives
The visibility of a variable is not retained A @private variable could become @protected
or @public The refactoring tool warns you if any of the subclasses already have a variable or method with the same name, but it won ’ t prevent you from applying the transformation The result will be classes with duplicate methods
You can only migrate a variable or method to one or more of its immediate subclasses
➤
➤
➤
➤
➤
➤
➤
➤
➤
➤
➤
➤
➤
Trang 4200 ❘CHAPTER 10 REFACTORING
The modernize loop transformation is generally safe, because it simply refuses to be applied unless the control loop meets its rather strict prerequisites It is still possible, however, to trick the refactoring tool into transforming a loop that contains abnormal behavior hidden
in preprocessor macros
The use properties transformation may produce @property directives whose attributes (that
is, assign , retain , copy , nonatomic ) do not agree with the implementation of the existing getter or setter methods Review each new @property directive and confi rm that your getter and setter fulfi ll the property contract, correcting one or the other as appropriate
The transformation will not create @synthesize directives for properties that already have KVC getter and setter methods, even if the getter and setter methods use generic patterns
You may want to delete simplistic getter and setter methods before converting your project and let the transformation insert the more modern @synthesize directives
Unlike the encapsulate transformation, use properties will not replace direct references
to instance variables ( ivar= ) with property “ dot ” syntax ( self.ivar= ) or getter and setter messages ( [self setIvar: ] ) You will need to search your code for direct instance variable references and determine which should be replaced with property accessors
No attempt is made to reduce the visibility of the existing instance variables After the transformation, consider making the instance variables @private This will also help identify direct references to the variable outside the class
SUMMARY
Changing the structure of your application isn ’ t always as simple as moving a defi nition or
performing a global search and replace The refactoring tool makes short work of many common
code changes, quickly and as intelligently as possible This doesn ’ t relieve you of the need to
confi rm the veracity of those changes, but it does relieve you of much of the tedium involved in
making them
Before every transformation, the refactoring tool gives you the option of making a snapshot of your
project The next chapter explains what snapshots are and how to use them in other circumstances
➤
➤
➤
➤
➤
Download at getcoolebook.com
Trang 5Snapshots
WHAT'S IN THIS CHAPTER?
Taking snapshots of your entire project Reviewing snapshots and comparing them with your working fi les Managing and restoring snapshots
If you ’ re like me, you hate to throw away code Most code, especially the stuff that works,
is a hard - won commodity that represents time, effort, expertise, and creativity The best way to improve your code, however, is to experiment with new approaches — which often means abandoning or discarding the code you ’ ve already written Making copies of your source fi les or saving snippets of old code as comments is both awkward and time consuming
Enter snapshots Snapshots let you have it both ways: you can keep your existing code while simultaneously replacing it with new, experimental code
In simple terms, a snapshot is an archived copy of the source fi les in your project It quickly
preserves their current state so you are free to make changes to your project — even radical ones — secure in the knowledge that you can always revert back to the saved version at any time You can make as many snapshots as you like You can easily see what changes you ’ ve made, as shown in Figure 11 - 1, by comparing your working project fi les to those in a snapshot You can revert your changes to any previous snapshot on a change - by - change basis,
by fi le, or perform a wholesale restore of the entire project
➤
➤
➤
11
Trang 6202 ❘CHAPTER 11 SNAPSHOTS
Snapshots encourage experimentation by making it easy to save and contrast existing code with new
code There ’ s very little risk in rewriting a collection loop to improve performance when Xcode will
preserve the previous implementation Take a snapshot, rewrite the loop, and test its performance Is
it an improvement? Keep the new code Not an improvement? Restore the saved snapshot and move
on or try a different approach It ’ s that simple
Snapshots resemble a source control system, but shouldn ’ t be treated as one Each snapshot is
(conceptually) a complete and independent copy of your entire project Snapshots are not deltas,
so they won ’ t preserve a history or audit trail of your changes — although you can compare two
snapshots Snapshots are cached on your local fi lesystem; they cannot be transferred to another
user, nor is any snapshot information preserved in the project itself Snapshots are intended to be
a spontaneous method of marking your progress Snapshots can be used independently of, or in
addition to, the source control management features See the “ Source Control vs Snapshots ” section
of Chapter 21 about issues that can arise when mixing snapshots and source control operations
TAKING SNAPSHOTS
You have four ways of taking a snapshot:
Choose the File ➪ Make Snapshot (Control+Command+S) command Add a snapshot from the snapshot window
Take a snapshot via the refactoring tool Restore a snapshot
➤
➤
➤
➤
FIGURE 11 - 1
Download at getcoolebook.com
Trang 7Snapshots occur immediately; there are no dialogs or other overt indications that a snapshot was taken Each snapshot has a name and an optional description; but when initially added all snapshots are given a generic name that describes how the snapshot was made (menu command, snapshot window, refactor transformation, or restore) and the date If you want to make a snapshot memorable, rename it or add a comment to the freshly created snapshot in the snapshot window (File ➪ Snapshots)
When Xcode takes a snapshot, it preserves the project source fi les contained within your project folder If you have added source items to your project whose
fi les are located outside of your project folder, those fi les will not be included
in the snapshot If you want resources outside of your project folder (like other projects) to be included in your snapshots, consider relocating your project’s root folder (see Chapter 21) or use the snapshot feature of the organizer (see Chapter 22).
The minimal user interaction is intended to make snapshots a seamless part of your development workfl ow, not another interruption to it On modern computer systems, snapshots are fast and inexpensive Get into the habit of taking a snapshot before starting any atomic change to your project Taking snapshots should become second nature, just as many developers save their fi les at strategic times You will want to visit your snapshots occasionally to dispose of old and intermediate snapshots
MANAGING SNAPSHOTS
Snapshots are managed in the snapshot window (File ➪ Snapshots) The snapshot window is typically collapsed and shows only the summary of snapshots, as shown in Figure 11 - 2 Click the Show Files button in the toolbar to display change information that was shown in Figure 11 - 1
The snapshot window is the central interface for browsing, commenting, examining, comparing, and deleting your snapshots These actions are explained in the following sections
Commenting on Snapshots
Snapshots are initially named by the method they were taken (via the main menu, before a refactoring, and so on) FIGURE 11-2