Caton optimization

  • CPU and GPU play an important role in screen imaging
    • CPU: object creation and destruction, object property adjustment, layout calculation, text calculation and typesetting, image format conversion and decoding, Core Graphics
    • GPU: Texture rendering

The main idea of optimization is to reduce CPU and GPU resource consumption as much as possible

CPU optimization

  • Try to use lightweight objects, such as CALayer instead of UIView, for places that don’t handle events
  • Do not frequently call UIView properties, such as frame, bounds, and Transform properties. Calculate them in advance, and adjust the corresponding properties once if necessary. Do not change them multiple times
  • AutoLayout consumes more CPU resources than setting the frame directly
  • The image size should be exactly the same as the UIImageView size
  • Controls the maximum number of concurrent threads
  • Try to put time-consuming operations into child threads (text processing: sizing and drawing, image processing: decoding and drawing)
/ / text calculation [@ "text" boundingRectWithSize: CGSizeMake (100, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:nil]; [@"text" drawWithRect:CGRectMake(0, 0, 100) 100) options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:nil];Copy the code
- (void)image { UIImageView *imageView = [[UIImageView alloc] init]; imageView.frame = CGRectMake(100, 100, 100, 56); [self.view addSubview:imageView]; self.imageView = imageView; dispatch_async(dispatch_get_global_queue(0, 0), CGImage = [UIImage imageNamed:@"timg"].CGImage; CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage) & kCGBitmapAlphaInfoMask; BOOL hasAlpha = NO; if (alphaInfo == kCGImageAlphaPremultipliedLast || alphaInfo == kCGImageAlphaPremultipliedFirst || alphaInfo == kCGImageAlphaLast || alphaInfo == kCGImageAlphaFirst) { hasAlpha = YES; } // bitmapInfo CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; // size size_t width = CGImageGetWidth(cgImage); size_t height = CGImageGetHeight(cgImage); // context CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, CGColorSpaceCreateDeviceRGB(), bitmapInfo); // draw CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); / / get CGImage CGImage = CGBitmapContextCreateImage was obtained from the context (context); // into UIImage UIImage *newImage = [UIImage imageWithCGImage:cgImage]; // release CGContextRelease(context); CGImageRelease(cgImage); // back to the main thread dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = newImage; }); }); }Copy the code

GPU optimization

  • Minimize the number of views and levels
  • Try to avoid displaying a large number of images in a short time
  • The maximum texture size that GPU can process is 4096*4096. A single texture larger than this size will occupy CPU resources for processing
  • Reduce transparent views (alpha<1) and set Opaque to YES for opaque views
  • Avoid off-screen rendering
    • Current screen rendering, rendering in the screen cache currently used for display
    • Off-screen rendering: create a new cache for rendering outside the current screen cache

Off-screen rendering triggered

  • ShouldRasterize = YES
  • Mask the layer mask
  • Rounded corners: set layer.masksToBounds = YES and layer.cornerRadius greater than 0 at the same time. Consider cutting rounded corners with CoreGraphics, or use rounded images directly
/ / generated rounded picture - (UIImage *) ht_getCircleImage {/ / UIGraphicsBeginImageContext (self. The size); Equivalent (self. The size, the NO, 1) get the image quality is poor UIGraphicsBeginImageContextWithOptions (self. The size, YES, 0); CGContextRef ctx = UIGraphicsGetCurrentContext(); CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height); CGContextAddEllipseInRect(ctx, rect); CGContextClip(ctx); [self drawInRect:rect]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } / / / UIImage and rounded / / / @ param cornerRadius rounded corners - (UIImage *) ht_getCircleImageWithCornerRadius cornerRadius: (CGFloat) { / / YES, generated by the image background opaque 0: let the zoom factor of the picture according to the resolution of the screen and change UIGraphicsBeginImageContextWithOptions (self. The size, YES, 0); CGContextRef ctx = UIGraphicsGetCurrentContext(); CGRect rect = CGRectMake(0.0, 0.0, self.size. Width, self.size. Height); CGContextAddPath(ctx, [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius].CGPath); CGContextClip(ctx); [original drawInRect:rect]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; }Copy the code

Optimize the power consumption

  • Use less timer
  • I/O operation optimization:
    • Batch write
    • Dispatch_io is used for reading and writing large amounts of data
    • Consider databases (SQLite, CoreData) for large data volumes
  • Network optimization:
    • Use the cache
    • Breakpoint continuingly
    • Do not send network requests when the network is unavailable
    • Set an appropriate timeout for network requests
  • Location optimization
    • Try not to update the location in real time. Turn off the location service after locating
    • Try to reduce the positioning accuracy, such as try not to use the highest accuracy kCLLocationAccuracyBest
    • Need background position, try to set up pausesLocationUpdatesAutomatically to YES, if the user is unlikely to move the system will automatically suspended position update
    • Need background position, try to set up pausesLocationUpdatesAutomatically to YES, if the user is unlikely to move the system will automatically suspended position update

Start the optimization

  • Print APP startup time analysis by adding environment variables (Edit Scheme -> Run -> Arguments)
    • DYLD_PRINT_STATISTICS is set to 1

    • If you need more detailed information, set DYLD_PRINT_STATISTICS_DETAILS to 1

The cold start of an APP is divided into three stages

  • Dyld: Apple dynamic linker for loading Mach-O files (executables, dynamic libraries)

    • The executable of the APP is loaded, and the dependent dynamic library is loaded recursively
    • When dyLD finishes loading the executable and dynamic libraries, it notifies Runtime for further processing
  • runtime

    • Map_images is called for parsing and processing of executable file contents
    • Call call_load_methods in load_images and call the +load method for all classes and categories
    • Initialize various objC structures (register objC classes, initialize class objects, and so on)
    • Calls the C++ static initializer and the __attribute__(((constructor)) modified function
    • Up to this point, all symbols (Class, Protocol, Selector, IMP,…) in executables and dynamic libraries All have been successfully loaded into memory in the format managed by the Runtime
  • main

Optimal point

Reduce the number of Objc classes, classes, and selectors. Reduce the number of C++ virtual functions. Swift uses structs as much as possible Replace all __attribute__(((constructor)), C++ static constructors, and ObjC + loads with the +initialize method and dispatch_once method, delaying some operations as much as possible without affecting the user experience. Don't put it all in the finishLaunching method and load it on demandCopy the code

Ipa volume optimization

  • Regular image code generation (solid color image, color gradient image)
  • Lossless compression of pictures
  • Remove unused resources: github.com/tinymind/LS…
  • Use AppCode (www.jetbrains.com/objc/) to detect unused… -> Code -> Inspect Code