iPhone 编程开发设计与优化

Part 2: Working with Data Efficiently Advanced Performance Optimization on iPhone OS Ben Nham iPhone Performance 2 Introduction • Focus on working with data efficiently ■ In-memory data structures ■ Serialization and deserialization • Measurement tools • Mental models • Best practices 3 What You’ll Learn • Memory • Foundation performance • Filesystem • Databases • Scaling 4 Memory 5 Not a Desktop OS • Limited memory • Virtual memory, but no swap file • Low memory notifications RAM iPhone 4 iPad iPhone 3GS 3rd Generation iPod Touch 2nd Generation iPod Touch iPhone 3G Mac Mini 512 MB 256 MB 256 MB 256 MB 128 MB 128 MB 2048 MB 6 Memory Overview 2007 0 32 64 96 128 206668103612 Graphics Wired Daemons SpringBoard Phone Mail iPod Safari iPhone 3G 7 Virtual Memory Paging • The kernel deals with memory in 4KB chunks called pages • Each application has a 32-bit address space broken into pages • A page can be in several states ■ Nonresident ■ Resident and clean ■ Resident and dirty 8 Virtual Memory Residency • A page is resident if it is present in physical memory • It is nonresident otherwise ■ If a nonresident page is accessed, a page fault occurs and the page becomes resident 9 Virtual Memory Dirty pages • A resident page can be clean or dirty ■ Resident anonymous memory is always dirty (e.g., malloc) ■ Resident file-backed memory is usually clean ■ Becomes dirty if modified • A clean page can be swapped out for “free” ■ But it still contributes to memory pressure in the system • On iPhone OS, dirty pages cannot be swapped out! ■ Excessive amounts of dirty pages cause memory warnings and eventually the out-of-memory killer 10 NonresidentResident Dirty NonresidentResident Dirty Malloc Memory • Malloc memory is anonymous (not backed by a file) • When it is resident, it is dirty char *p = valloc(2 * 4096); p[0] = 1; p[4096] = 2; Nonresident Nonresident Nonresident Resident Dirty 11 NonresidentResident Clean Nonresident Example File-backed memory • If mapped read-only, file backed memory will be clean when resident • Code from app binary is mapped read-only NSData *data = [NSData dataWithContentsOfMappedFile:file]; char *p = (char *)[data bytes]; printf("%c", p[0]); printf("%c", p[4096]); Resident Clean Nonresident Resident Clean Nonresident Nonresident File 12 VM Tracker Taking snapshots • A VM snapshot shows how memory usage is distributed across regions of memory usage • To take a snapshot ■ Ask the instrument to periodically take snapshots automatically ■ Manually trigger a snapshot (default) • Works best in simulator right now 13 VM Tracker Check samples over time 14 VM Tracker Check growth in dirty size of regions • Growing dirty __DATA ■ Copy on write faults ■ Global variables that are modified • Growing malloc ■ Check for leaks ■ Use Allocations tool to find backtraces • Core Animation ■ Possible view leaks • TC malloc ■ At least ~ 200KB used by WebKit 15 Other Memory Measurement Tools 16 Low Memory Warnings Don’t ignore the signs • Any process may create low memory conditions ■ If the combined dirty memory usage of all processes becomes too high, a low memory notification is sent • Expect memory warnings (normal part of the system) • You must respond to low memory warnings! ■ Failure to respond can cause app termination 17 Low Memory Warnings Total Dirty Memory Warning: Apps receive notification Urgent: Background apps exit, frontmost app warned Critical: Frontmost app exits 18 Low Memory Warnings Taking action • Release any objects that can be reconstructed • Release cached objects • Unload cached resource files 19 Low Memory Warnings Taking action • Don’t ask user to do anything (they can’t!) 20 Low Memory Warnings Responding to low memory warnings • In UIViewController subclasses ■ Override viewDidUnload • In your app delegate ■ Implement applicationDidReceiveMemoryWarning: method • Direct notifications ■ Register for UIApplicationDidReceiveMemoryWarningNotification 21 Low Memory Warnings Unloading views • -[UIViewController viewDidUnload] is called when the the controller’s -view is unloaded • But it needs help releasing views retained in instance variables 22 Navigation Stack Unloading views Low Memory Warnings ComposeViewController PhotoViewController 23 UIButton UILabel UIView UILabel UITextViewSubviews IBOutlet ComposeViewController Low Memory Warnings 24 @interface ComposeViewController : UIViewController { UILabel *titleLabel; UILabel *locationLabel; UITextView *textView; UIButton *imageButton; } @property (nonatomic, retain) IBOutlet UILabel *titleLabel; @property (nonatomic, retain) IBOutlet UILabel *locationLabel; @property (nonatomic, retain) IBOutlet UITextView *textView; @property (nonatomic, retain) IBOutlet UIButton *imageButton; @end - (void)viewDidUnload { self.titleLabel = nil; self.locationLabel = nil; self.textView = nil; self.imageButton = nil; [super viewDidUnload]; } Low Memory Warnings Unloading views 25 Low Memory Warnings UIView Subviews UIButton UILabel UILabel UITextView IBOutlet ComposeViewController 26 Low Memory Warnings Simulating memory warnings • Test memory warnings with the simulator 27 Interacting with Multitasking • Low memory notifications are not sent when an app backgrounds • Explicitly release resources in response to going into the background if not performing a background task ■ When delegate’s applicationDidEnterBackground: is called ■ After receiving UIApplicationDidEnterBackgroundNotification • Apps that use less memory have a lower chance of being terminated after suspension 28 Image Memory Choosing the right method • Use +[UIImage imageNamed:] with images that are used in UI elements • Use +[UIImage imageWithContentsOfFile:] for everything else 29 Image Memory Creating thumbnails with ImageIO • CGImageSource can efficiently create thumbnails from data or file paths // Assuming source is a CGImageSourceRef... CFDictionaryRef options = (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform, (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent, (id)[NSNumber numberWithInt:size], (id)kCGImageSourceThumbnailMaxPixelSize]; CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(source, 0, options); if (imageRef) { image = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); } • Refer to Creating a Thumbnail Image in the Image I/O Programming Guide for more details 30 Memory Summary • Drive down the dirty memory usage of your app • Respond to memory warnings • Release resources when entering the background • Additional resources ■ Introduction to Instruments User Guide ■ man vmmap to understand VM Tracker in detail ■ Memory Management Programming Guide 31 Foundation Performance 32 NSMutableArray Asymptotic performance • Textbook performance characteristics ■ Indexed access: O(1) ■ Insertion/deletion in middle: O(N) ■ Insertion/deletion at end: Amortized O(1) • Unique performance characteristics ■ Insertion/deletion at beginning: Amortized O(1) ■ Can be used as a queue ■ Currently becomes a tree at about 250,000 elements ■ Access to individual elements becomes O(log N) ■ Unlikely to happen in your application ■ Could change in the future 33 NSMutableString Asymptotic performance • Indexed access: O(1) • Insertion/deletion in middle: O(N) • Insertion/deletion at end: Amortized O(1) 34 NSMutableDictionary Asymptotic performance • With a good hash function ■ Lookup, insertion, replacement, removal: O(1) on average • With a bad hash function ■ Degenerates into an array or worse ■ Lookup: O(N) 35 NSMutableDictionary Hash functions • Bad hash functions • Return dispersed values ■ For objects that contain Foundation objects, XORing the -hash of each object is usually good enough - (NSUInteger)hash { return random(); } @interface ArrayDict : NSObject NSArray *_array; NSDictionary *_dict; @end - (NSUInteger)hash { return [_array hash] ^ [_dict hash]; } - (NSUInteger)hash { return 42; } 36 NSMutableDictionary Hash functions • Make sure the hash function runs relatively quickly ■ When a dictionary grows, it has to rehash the existing values ■ Stick to relatively fast operations: add, shift, mask, XOR • Remember the API contract ■ Keys are copied with NSCopying when calling -setObject:forKey: ■ Objects which are -isEqual: must return the same -hash 37 Avoiding Integer Boxing • NSIndexSet can store ranges of indices efficiently without boxing • CoreFoundation collections can store pointer-sized integers natively ■ Works for all collection types NSUInteger key = 0, value = 1; CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); CFArrayAppendValue(array, (void *)key); CFMutableSetRef set = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL); CFSetAddValue(set, (void *)key); CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); CFDictionaryAddValue(dict, (void *)key, (void *)value); 38 Avoiding Integer Boxing 3 ms 3 ms 30 msNSMutableSet Adding 1000 NSNumbers CFMutableSet Adding 1000 integers NSMutableIndexSet Adding 1000 integers 39 Bulk Operations Using the highest-level API • Instead of many repeated calls to -[NSArray objectAtIndex:]: • Instead of many repeated calls to -[NSString characterAtIndex:]: for (id obj in array) { ... } - (NSArray *)arrayByAddingObjectsFromArray:(NSArray *)otherArray; - (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes; - (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))block; etc. - (void)getCharacters:(unichar *)buffer range:(NSRange)range; - (BOOL)hasPrefix:(NSString *)searchString; - (NSRange)rangeOfString:(NSString *)searchString; - (void)enumerateLinesUsingBlock:(void (^)(NSString *line, BOOL *stop))block; etc. 40 NSRegularExpression • Convenience methods in NSString are fine for one-off searches [string rangeOfString:pattern options:NSRegularExpressionSearch]; • For repeated searches, create and reuse an NSRegularExpression object - (void)enumerateMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range usingBlock:(void (^)(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop))block; • By default, block is called back for every match ■ Use NSMatchingReportProgress to be called back periodically ■ Set the stop out parameter to YES to stop the search 41 Avoiding Expensive Initialization Costs • Some classes are expensive to initialize and should not be initialized or mutated repeatedly if used multiple times ■ NSRegularExpression, NSDataDetector ■ NSDateFormatter, NSNumberFormatter - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // After creating or reusing a cell... NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"MMMM"]; [[cell textLabel] setText:[formatter stringFromDate:date]]; [formatter release]; return cell; } 42 Avoiding Expensive Initialization Costs • Instead, lazily create a formatter for each style used, and keep using it static NSDateFormatter *__monthFormatter = nil; NSDateFormatter *MonthFormatter() { if (__monthFormatter == nil) { __monthFormatter = [[NSDateFormatter alloc] init]; [__monthFormatter setDateStyle:@"MMMM"]; } return __monthFormatter; } [[cell textLabel] setText: [MonthFormatter() stringFromDate:date]]; 43 Avoiding Expensive Initialization Costs Some gotchas • Date and number formatters do not automatically update when the locale changes, so this must be handled manually if they are cached NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserverForName:NSCurrentLocaleDidChangeNotification object:self queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { [__monthFormatter release]; __monthFormatter = nil; }]; • Date and number formatters are not thread-safe ■ But NSRegularExpression, NSDataDetector are thread-safe 44 Avoiding Expensive Initialization Costs 16 ms 85 ms100 NSDateFormatters Each formatting one date Single NSDateFormatter Formatting 100 dates 45 Property Lists Use the binary format • Binary plists are 2–3x faster to decode than XML plists • Plist resources in the app bundle are automatically converted to binary format at build time • For plists created at run time, use NSPropertyListSerialization -[NSArray writeToFile:atomically:] -[NSDictionary writeToFile:atomically:] -[NSString writeToFile:atomically:encoding:error:] NSData *data = [NSPropertyListSerialization dataWithPropertyList:dictionary format:NSPropertyListBinaryFormat_v1_0 options:0 error:NULL]; [data writeToFile:path atomically:YES]; 46 Property Lists Proper usage • Plists are great for storing small bits of data, like configuration files ■ Up to tens of kilobytes is generally fine • Not an incremental format ■ Entire object graph in the plist must be recreated in memory at deserialization time ■ Entire object graph must be traversed and rewritten at serialization time • Use another file format or a database to incrementally deserialize or serialize information 47 NSCoding • Only use this for small object graphs ■ Large object graphs can take hundreds of milliseconds to read or write ■ Measure using Time Profiler • NIBs use NSCoding ■ Avoid stuffing NIBs with unnecessary top-level objects 48 UINib • Avoids deserializing NIBs from scratch for commonly accessed resources • Useful for table view cell NIBs - (UITableViewCell *)tableView:(UITableView *)view cellForRowAtIndexPath:(NSIndexPath *)idx { AppCell *cell = (AppCell *)[tableView dequeueReusableCellWithIdentifier:@"AppCell"]; if (cell == nil) { // load cell from NIB file } } 49 UINib if (cell == nil) { if (!cellNib) // instance var cellNib = [UINib nibWithNibName:@"Cell" bundle:nil]; NSArray *topLevelObjects = [cellNib instantiateWithOwner:self options:nil]; cell = [topLevelObjects objectAtIndex:0]; } • New method of using UINib: if (cell == nil) { NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"Cell" owner:self options:nil]; cell = [topLevelObjects objectAtIndex:0]; } • Old method of using NSBundle: 50 UINib 1.9 ms 2.8 msNSBundle loadNibNamed:owner:options: UINib instantiateWithOwner:options: Time to load one table view cell 51 Foundation Performance Summary • Foundation types generally have good performance if used correctly • Understand the API ■ Use a higher-level methods if possible ■ Avoid expensive re-initialization of certain classes ■ Use plists and NSCoding for small object graphs • Additional resources ■ Collections Programming Topics ■ Property List Programming Guide ■ Archives and Serialization Programming Guide ■ Resource Programming Guide 52 Filesystem 53 Filesystem • Use to ensure I/O activity seems sane ■ Extended detail shows backtrace that caused I/O • Doesn’t yet measure bytes that are demand-paged from mapped files Measuring performance with System Usage 54 Filesystem Best practices • Test apps on multiple kinds of devices ■ Significant differences in read/write performance • Avoid doing long I/Os on main thread • For extremely large files, avoid +[NSData dataWithContentsOfFile:] ■ Reads the entire file eagerly into a dirty memory buffer ■ Alternatives ■ Demand page data with +[NSData dataWithContentsOfMappedFile:] ■ Incrementally read data with -[NSFileHandle readDataOfLength:] • Avoid repeatedly opening or checking attributes of a path ■ Incurs cost for path permissions check 55 Filesystem Accessing paths • Get read-only paths to application bundle with NSBundle • Store preferences in application sandbox with NSUserDefaults • Get writable paths in your application sandbox with NSSearchPathForDirectoriesInDomains or NSTemporaryDirectory • Do not write outside of your application’s sandbox Persists Across Launches Persists Across Updates Backed up by iTunes NSDocumentDirectory NSUserDefaults NSCachesDirectory NSTemporaryDirectory ✓ ✓ ✓ ✓ ✓ ✓ ✓ 56 Filesystem Summary • Use System Usage to determine if there are filesystem bottlenecks in your app • For large files, prefer interfaces and formats that read incrementally instead of all at once • Perform long I/Os off the main thread • Choose the correct path to avoid unnecessary backups 57 Databases 58 Databases Overview • Allow incremental reading and writing of data • Great for transactional storage of structured information • Use Core Data if possible ■ Provides automatic schema management ■ Has iPhone specific enhancements (e.g., table view section caching) • Native SQLite library is available, but is much more low level • Understand data modeling ■ “Object Modeling” in the Cocoa Fundamentals Guide 59 SQLite Profiling queries • Profile queries with sqlite3_profile to dump query times to console sqlite3_profile(conn, &profile, NULL); static void profile(void *context, const char *sql, sqlite3_uint64 ns) { fprintf(stderr, "Query: %s\n", sql); fprintf(stderr, "Execution Time: %llu ms\n”, ns / 1000000); } • Console output Query: SELECT StartTime, Duration, Title FROM Events ORDER BY StartTime DESC; Execution Time: 250 ms Query: SELECT Date, Title, Completed FROM Todos ORDER BY Date DESC; Execution Time: 150 ms 60 SQLite Prepared statements • Statement objects are backed by a program interpreted by SQLite ■ The EXPLAIN command shows the actual program • Cache prepared statements that you plan to use over and over ■ Use bind parameters to change the statement’s behavior • Don’t cache prepared statements you don’t plan to reuse 61 SQLite Query plans • Use EXPLAIN QUERY PLAN and EXPLAIN to understand the behavior of a statement ■ Execute the commands using the sqlite3 tool on your host • Order of tables in a JOIN can affect query plan • Watch out for transient tables ■ EXPLAIN will show an OpenEphemeral instruction ■ Common causes ■ Sorting without an index ■ Subselects ■ Can make the first sqlite3_step take a long time 62 SQLite Sample schema ROWID Name Integer Primary Key Text Album ROWID Title Path AlbumID AlbumOrder ArtistID Integer Primary Key Text Text Integer Foreign Key Integer Integer Foreign Key Track ROWID Name Integer Primary Key Text Artist 63 ROWID Title Path AlbumID Album Order ArtistID 1 A T 3 1 1 2 B U 3 2 2 3 C V 2 3 3 4 D X 2 1 2 5 E Y 2 2 3 6 F Z 1 1 1 ROWID Title Path AlbumID Album Order ArtistID 1 A T 3 1 1 2 B U 3 2 2 3 C V 2 3 3 4 D X 2 1 2 5 E Y 2 2 3 6 F Z 1 1 1 Title Path AlbumID Album Order ArtistID C V 2 3 3 D X 2 1 2 E Y 2 2 3 SQLite Naive query plan sqlite> EXPLAIN QUERY PLAN ...> SELECT * FROM Track WHERE AlbumID=2 ORDER BY AlbumOrder; 0|0|TABLE Track • Select all tracks in an album, ordered by track number • Table scan for WHERE, plus a sort of a transient table for ORDER BY Track Transient Table Title Path AlbumID Album Order ArtistID D X 2 1 2 E Y 2 2 3 C V 2 3 3 64 ROWID Title Path AlbumID Album Order ArtistID 1 A T 3 1 1 2 B U 3 2 2 3 C V 2 3 3 4 D X 2 1 2 5 E Y 2 2 3 6 F Z 1 1 1 ROWID Title Path AlbumID Album Order ArtistID 1 A T 3 1 2 B U 3 2 2 3 C V 2 3 3 4 D X 2 1 2 5 E Y 2 2 3 6 F Z 1 1 1 Title Path AlbumID Album Order ArtistID C V 2 3 3 D X 2 1 2 E Y 2 2 3 SQLite Better query plan sqlite> CREATE INDEX TrackAlbumIDIndex ON Track(AlbumID); sqlite> EXPLAIN QUERY PLAN ...> SELECT * FROM Track WHERE AlbumID=2 ORDER BY AlbumOrder; 0|0|TABLE Track WITH INDEX TrackAlbumIDIndex • After adding an index to help finding all tracks in an album • Finds all tracks in an album using an index • ORDER BY still handled by sorting a transient table Track Transient Table Title Path AlbumID Album Order ArtistID D X 2 1 2 E Y 2 2 3 C V 2 3 3 AlbumID ROWID 1 6 2 3 2 4 2 5 3 1 3 2 Index 65 SQLite Best query plan sqlite> CREATE INDEX TrackAlbumIDOrderIndex ON Track(AlbumID, AlbumOrder); sqlite> EXPLAIN QUERY PLAN ...> SELECT * FROM Track WHERE AlbumID=? ORDER BY AlbumOrder; 0|0|TABLE Track WITH INDEX TrackAlbumIDOrderIndex ORDER BY • Select all tracks in an album, ordered by track number • Finds all tracks in an album in logarithmic time using the index • Uses second column in index to iterate over Track in sorted order ROWID Title Path AlbumID Album Order ArtistID 1 A T 3 1 1 2 B U 3 2 2 3 C V 2 3 3 4 D X 2 1 2 5 E Y 2 2 3 6 F Z 1 1 1 Track AlbumID Album Order ROWID 1 1 6 2 1 4 2 2 5 2 3 3 3 1 1 3 2 2 Index 66 SQLite Query plan with joins sqlite> CREATE INDEX TrackAlbumIDOrderIndex ON Track(AlbumID, AlbumOrder); sqlite> EXPLAIN QUERY PLAN ...> SELECT * FROM Track JOIN Artist ON ArtistID=Artist.ROWID ...> WHERE AlbumID=? ORDER BY AlbumOrder; 0|0|TABLE Track WITH INDEX TrackAlbumIDOrderIndex ORDER BY 1|1|TABLE Artist USING PRIMARY KEY • Same as previous queries, but join onto Artist by logarithmically looking up Artist’s primary key 67 Page 25 Page 20 Page 45 Page 30 Page 36 Page 32 ... Page Cache 256 Pages (1MB) by default Page 4 Page 1 Page 8 Page 10 Page 1 Page 4 Page 8 Page 10 Table and Index B-Trees SQLite Understanding the page cache Page 1 Page 2 Page 3 Page 4 Page 5 ... Database File Page 1 Page 4 Page 8 Page 10 68 SQLite Paged I/O guidelines • I/O is done in page-sized increments ■ Surround batch INSERTs or UPDATEs with transactions • Don’t store large arbitrarily sized binary objects in the database ■ Small (< 2k or so) BLOBs are fine ■ Large BLOBs work, but aren’t optimal ■ Crowd out other data from the page cache ■ Write traffic is doubled because of transactions ■ Consider storing pointers to the filesystem in the DB instead 69 SQLite Using transactions 0.04 MB 24 MBAutocommit 1000 updates Single transaction 1000 updates Total amount of I/O 70 Databases Summary • Use CoreData if possible • Find problematic queries using sqlite3_profile • Understand problematic queries with EXPLAIN QUERY PLAN • Use transactions where appropriate • Scale gracefully with large data sets • Additional resources ■ Core Data Programming Guide ■ Introduction to SQLite by D. Richard Hipp (on YouTube) ■ SQLite Documentation on SQLite.org 71 Scaling 72 Scaling • Applications should scale gracefully in the face of large data sets • Think about the minimum amount of work needed to make critical methods fast • Case study: Contacts 73 Scaling in Contacts 2.25 s 2.18 s 2.14 s30 Contacts 300 Contacts 3000 Contacts Launch Time on iPhone 3G 74 Scaling in Contacts Make critical methods fast - tableView:numberOfRowsInSection: - tableView:titleForHeaderInSection: - numberOfSectionsInTableView: Loading sections - tableView:sectionIndexTitlesForTableView: Loading the index bar - tableView:cellForRowAtIndexPath: Loading visible cells 75 Scaling in Contacts Loading sections quickly • Naive: load entire data set and group afterwards • Better: cache the section counts ■ Tricky to do right for all localizations: see DerivedProperty example ■ Contacts uses a separate table for section counts, maintained by triggers ■ CoreData users get this for free -[NSFetchedResultsController initWithFetchRequest:(NSFetchRequest *)fetchRequest managedObjectContext:(NSManagedObjectContext *)context sectionNameKeyPath:(NSString *)sectionNameKeyPath cacheName:(NSString *)name] 76 Scaling in Contacts Loading the index bar quickly • Approach 1: always loads the same index bar ■ Contacts does this: always loads A–Z and # • Approach 2: change the index bar titles based on section count ■ Should be fast if section loading is fast 77 Scaling in Contacts Loading visible cells quickly • Do not table scan just to retrieve one cell’s worth of information ■ Bring in data in small chunks ■ LIMIT/OFFSET is not particularly efficient in SQLite, but works if iterating over a small index ■ Can also use scrolling cursor method SELECT VisibleName FROM People ORDER BY LastName, FirstName LIMIT 20 OFFSET 0; CREATE INDEX PeopleLastFirstOrder (LastName, FirstName); • Make sure that proper indices are in place to avoid sorting a transient table 78 Scaling Summary • Test and profile apps with different data set sizes • Only bring in the data necessary to display a view ■ Avoid bringing in the entire data set at view loading time 79 Summary • Reduce dirty memory usage • Adhere to Foundation API best practices • Profile filesystem and database activity • Test apps on different devices and varying sizes of data sets 80 Michael Jurewitz Developer Tools Evangelist jurewitz@apple.com Documentation iPhone OS Programming Guide http://developer.apple.com/iphone Apple Developer Forums http://devforums.apple.com More Information 81 Performance Optimization on iPhone OS Presidio Thursday 2:00PM Advanced Performance Optimization on iPhone OS, Part 1 Mission Thursday 3:15PM Related Sessions Advanced Performance Analysis with Instruments Mission Thursday 9:00AM Advanced Memory Analysis with Instruments Presidio Thursday 11:30AM Optimizing Core Data Performance on iPhone OS Presidio Thursday 4:30PM Accelerate Framework for iPhone OS Nob Hill Tuesday 11:30AM 82 83 84 85




需要 15 金币 [ 分享pdf获得金币 ] 4 人已下载





下载需要 15 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!