Monday, September 22, 2014

Improving performance when dealing with layer properties or Core Animation

Prior or subsequent to this post I recommend you guys to take a look in to one of my another post related to enhancing performance and memory management of an iOS app here,
Before going in to depth there is a quick snapshot below for those who don’t want to dig in but just want a quick instant solution w.r.t improving performance when dealing with layer properties of UIView,
1)   Use Opaque Layers Whenever Possible. i.e; set opaque property to YES, whenever it is possible.
2)   Use Simpler Paths for CAShapeLayer Objects i.e; While drawing shape layers it is recommended to break up complex shapes into simpler shapes. 
3)   Specify a Shadow Path when adding a shadow to your view’s layer. i.e; make use of layers shadowPath property when you are dealing with layers shadow effect. 
4)   Use Asynchronous Layer rendering whenever required (if and only if really required). i.e; set drawsAsynchronously boolean property to YES whenever required, so as to process your drawing commands asynchronously in a background thread. 
5)   Use  shouldRasterize boolean property, If you have a complex view (i.e. relatively expensive to re-render) that you are animating, but for which the animated view is not itself changing, rasterizing the layer can improve the performance by not re-rendering the layer all the time.
shouldRasterize will consume memory for saving a rasterized image in memory, so use this whenever it is really required.
Bit more description/explanation on above points,
1) Use Opaque Layers Whenever Possible. i.e; set opaque property to YES, whenever it is possible.
- A Boolean value indicating whether the layer contains completely opaque content.
- The default value of this property is NO.
- Declare Views as Opaque Whenever Possible
Setting the opaque property of your layer to YES lets Core Animation know that it does not need to maintain an alpha channel for the layer. Not having an alpha channel means that the compositor does not need to blend the contents of your layer with its background content, which saves time during rendering.
Setting the value of this property to YES for a custom view tells UIKit that it does not need to render any content behind your view. Less rendering can lead to increased performance for your drawing code and is generally encouraged. Of course, if you set the opaque property to YES, your view must fills its bounds rectangle completely with fully opaque content.
The iPhone GPU is a tile-based renderer. If an overlaying layer is completely opaque over an entire tile, the GPU can ignore setting up and processing any graphics commands related to the layer underneath for that particular tile, in addition to not having to do compositing of the pixels in that tile.
2) One way to minimize drawing time for shape layers is to break up complex shapes into simpler shapes. Using simpler paths and layering multiple CAShapeLayer objects on top of one another in the compositor can be much faster than drawing one large complex path. That is because the drawing operations happen on the CPU whereas compositing takes place on the GPU. 
3) shadowPath - The shape of the layer’s shadow.
when ever we are using CALayer animation or for shadow effects, we usually see a jerk in rendering those views if the transition view consists of huge graphics or utilizing more layer properties of view, especially in lower versions of iOS devices.
So as to avoid this jerk on rendering and optimizing performance we have to set shadowPath property when we are setting layers shadow effects.
- The default value of shadowPath property is nil, which causes the layer to use a standard shadow shape. If you specify a value for this property, the layer creates its shadow using the specified path instead of the layer’s composited alpha channel.
- Specifying an explicit path usually improves rendering performance. 
- The value of this property is retained using the Core Foundation retain/release semantics. 
- When you specify a path object for this property, Core Animation uses that shape to draw and cache the shadow effect.
- For layers whose shape never changes or rarely changes, this greatly improves performance by reducing the amount of rendering done by Core Animation. 
Below code snippet is an example of setting shadow path for a view's layer which is having rounded corners,
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(10.0, 10.0)];
view.layer.shadowPath = path.CGPath;
Note: Your code will vary depending on the actual shape of your view. UIBezierPath has many convenience methods, you can get more info on this over here,
- You will need to update the layer’s shadowPath each time the bounds of your view change. And if you’re animating a change to bounds, then you will also need to animate the change to the layer’s shadowPath to match. 
- This property will drastically improves view rendering performance.
4) drawsAsynchronously - Use Asynchronous Layer rendering whenever required.
- drawsAsynchronously is a boolean indicating whether drawing commands are deferred and processed asynchronously in a background thread. 
- The default value for this property is NO. 
- Any drawing that you do in your delegate’s drawLayer:inContext: method or your view’s drawRect: method normally occurs synchronously on your app’s main thread. 
- In some situations, though, drawing your content synchronously might not offer the best performance. If you notice that your animations are not performing well, you might try enabling the drawsAsynchronously property on your layer to move those operations to a background thread. 
- Make sure your drawing code is thread safe whenever you are using drawsAsynchronously property. 
Note: Always, you should always measure the performance of drawing asynchronously before putting it into your code. 
5) shouldRasterize a boolean that indicates whether the layer is rendered as a bitmap before compositing 
- The default value of this property is NO. 
- When animating a complex set of layers that, themselves, are not changing, you can set shouldRasterize to YES, do the animation, and then turn off shouldRasterize. 
- If you have a complex view i.e; views expensive to re-render, that you are animating, but for which the animated view is not itself changing, rasterizing the layer can improve the performance by not re-rendering the layer all the time. 
- When the value of this property is YES, the layer is rendered as a bitmap in its local coordinate space and then composited to the destination with any other content. 
- Shadow effects and any filters in the filters property are rasterized and included in the bitmap. 
Note: shouldRasterize will consume memory for saving a rasterized image in memory, so use this whenever it is really required. 
Hope this post is helpful, any comments or suggestions are acceptable.

Wednesday, May 28, 2014

How to change status bar appearance in iOS 7

If your iOS applications minimum deployment target is iOS7.0 and above and if you have a dark background in your app then you can’t see the status bar text, since in iOS 7.0 and above status bar is transparent by default.
If the background of your view is black(or any dark color) then your status bar will not be visible, and looks something like below snapshot,

So here is a way to make your status bar text visible in dark background,
1) Add "View controller-based status bar appearanceproperty (key is UIViewControllerBasedStatusBarAppearance) to your applications info.plist and set the value to NO.

2) Go to your applications AppDelegate.m file and add the below code snippet in didFinishLaunchingWithOptions method,
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

If you have done with the above 2 points then you are 90% done except your status bar will not be visible during the time of splash screen display, 
To make your status bar visible when splash screen is displaying with dark background, just do the below mentioned step,

3) Add "Status Bar Style" property (key is UIStatusBarStyle) to your applications info.plist and set the value to “Transparent black style (alpha of 0.5)” (key is UIStatusBarStyleLightContent).

and we are 100% done now,,, :)

Now if you run your app you can able to see status bar as shown in the below snapshot,

Hope this post is helpful,any comments or suggestions are acceptable.

Wednesday, May 21, 2014

How to manage memory and enhance performance of an iOS app

One of the major things in any mobile application development is a memory management and performance enhancement,

Here is an instant guide or list of few crucial points w.r.t. enhancing our apps memory management, in turn performance optimizations in our iOS application, which I came across in my daily life and spent lot of time in fixing it, thought it would be great or it may save someones valuable time and energy if I share my note on this regard,

Here we go,
1) Better to make all IBOutlet objects as __weak reference in ARC environment. Except for those from file’s owner to top-level objects in a xib(nib or a storyboard scene) file which should be strong. Outlets that you create typically should be weak by default.

2) Instead of calling init constructor method every time when pushing/navigating to a view controller/view call init only once and until and unless the viewController object reference exists in memory use the same reference to navigate.

Ex:-  Suppose we are navigating from Home screen to a DetailViewController then create an iVar of DetailViewController globally and in your push method check for this iVar reference in memory and navigate like,
            detailVCObj = [[DetailViewController alloc] initWithNibName:@”DetailViewController” bundle:nil];//if object reference is not their in memory then only alloc and initilize
[self.navigationController pushViewController:detailVCObj animated:YES];

and suppose if you want to set some property values before pushing a view controller then create your custom getter and setter methods for those properties and call those methods before pushing view whenever you are following the above protocol.
By doing this(by following this protocol) it will optimize memory consumption during runtime. Follow this protocol even in ARC enabled projects.

        3) In ARC enabled projects, assign nil to all re-creatable objects and iVars after making use of these objectsso as to handle memory in an optimized manner.

In MRC (Manual Reference Counting) type of projects release re-creatable objects and iVars and then assign nil, after making use of these objects.
Assigning nil is equivalent to release and dereference in ARC.
a) In ARC enabled environment,  myiVar = nil;
b) In MRC environment,
[myiVar release];//releasing  object
myiVar = nil;//dereferencing the object

4)  Avoid using images up to the maximum extent in your app, and try to achieve the design by using colors wherever and whenever it is possible for you.

Since this will optimize both time complexity (load time for image is more compared to a UIColor) and space complexity (size of .ipa file will be reduced drastically if we avoid images).
If you are using images then based on your requirement and particular instance which UIImage method to use? refer this link

5) Make use of Singleton design pattern in your application wherever it is required and can be used.

Ex:- Suppose if you are calling some of the methods of a class frequently in your app, like a database model class in your app will be called frequently for either to insert or to fetch or to update different tables and its entities. Make this class as a singleton class so that even if you make n number of calls to this class methods single object will manipulate the functionality.
For more information on important design patterns in iOS refer this link

6) Whenever you are making a core data fetch call use includesPropertyValues where ever possible, refer this link for further details on this API.

7) Keep track of temporary memory buffers and reuse it, and don’t keep unused memory, free it up as soon as you are done using it.

8) iOS will automatically kills the background processes and apps which consumes more memory and causes memory pressure during low memory conditions, its every programmer responsibility to handle low memory conditions inside our app as-well.

During low memory conditions iOS UIKit framework will send few notifications to our app,
- Implement the applicationDidReceiveMemoryWarning: method of your application delegate.
- Override the didReceiveMemoryWarning method in your custom UIViewController subclass.
- Register to receive the UIApplicationDidReceiveMemoryWarningNotification notification.

Upon receiving any of these notifications, your handler method should respond by immediately removing strong references to objects
View controllers automatically remove references to views that are currently offscreen, but you should also override the didReceiveMemoryWarning method and use it to remove any additional references that your view controller does not need.

9) Use Instruments and Static Analyzer Xcode tools to check your app specific memory stats, and take further actions w.r.t. memory allocations, memory pressure and memory leaks.

Hope this post was helpful, any comments or suggestions are acceptable.