lecture 3-arc

50
Memory Management Quazi Ishtiaque Ahmed BJIT Limited Updated by: Saidul Islam Ziku

Upload: ziku-spartan

Post on 14-Apr-2017

46 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Lecture 3-ARC

Memory Management

Quazi Ishtiaque AhmedBJIT Limited

Updated by: Saidul Islam Ziku

Page 2: Lecture 3-ARC

Memory Management

Page 3: Lecture 3-ARC

Manual Retain Release (MRR). • Manually controlling object

ownership means to claim ownership of any object when need and remember to relinquish ownership when you’re done with it.

• Balancing every alloc, retain, and copy call with a release or autorelease on the same object.

• Without releasing an object, its underlying memory is never freed, resulting in a memory leak.

• Nevertheless releasing an object too many times, you’ll have what’s called a dangling pointer.

Page 4: Lecture 3-ARC

MRR Memory Leak

• Simple method for allocating a memory without releasing after usage. Causes Leak.

• The release method relinquishes ownership of an object by decrementing its reference count.

• [inventory release];

//main.m#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) {

@autoreleasepool { NSMutableArray *inventory = [[NSMutableArray alloc] init]; [inventory addObject:@"Honda Civic"]; NSLog(@"%@", inventory);

} return 0;

}

Page 5: Lecture 3-ARC

MRRRetain Removes Leaks

CarStore class implemention// CarStore.m #import "CarStore.h" @implementation CarStore { NSMutableArray *_inventory; } - (NSMutableArray *)inventory { return _inventory; } -(void)setInventory:(NSMutableArray *)newInventory {

_inventory = newInventory; } @end

CarStore class .h file// CarStore.h #import <Foundation/Foundation.h> @interface CarStore : NSObject - (NSMutableArray *)inventory; - (void)setInventory:(NSMutableArray *)newInventory; @end

Page 6: Lecture 3-ARC

MRRRetain Removes Leaks(Contd.)

Here carStore pointed the same object as inventory does. Thus after releasing inventory carStore property also be released.

//main.mNSMutableArray *inventory = [[NSMutableArray alloc] init]; [inventory addObject:@"Honda Civic"]; CarStore *superstore = [[CarStore alloc] init]; [superstore setInventory:inventory]; [inventory release]; NSLog(@"%@", [superstore inventory]);

Page 7: Lecture 3-ARC

MRRDangling Pointer

But retain that object causes not to update that object with new object passing the setter method.

-(void)setInventory:(NSMutableArray *)newInventory {

_inventory = [newInventory retain]; }

Page 8: Lecture 3-ARC

MRRDangling Pointer(Contd.)

if (_inventory == newInventory) { return; } NSMutableArray *oldValue = _inventory; _inventory = [newInventory retain]; [oldValue release]; }

Here How to remove dangling Pointing

Page 9: Lecture 3-ARC

ARC Defination• In Objective-C programming, Automatic Reference Counting (ARC) is a

memory management enhancement where the burden of keeping track of an object's reference count is lifted from the programmer to the compiler.

• In traditional Objective-C, the programmer would send retain and release messages to objects in order to mark objects for deallocation or to prevent deallocation.

• Under ARC, the compiler does this automatically by examining the source code and then adding the retain and release messages in the compiled code.

Page 10: Lecture 3-ARC

ARC Rules

• You cannot call retain, release, retainCount, autorelease, or dealloc.• The compiler automatically inserts the correct calls at compile time,

including messaging [super dealloc] in an override of dealloc.

Code example without ARC:- (void)dealloc {

[[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc];

} Code example with ARC: - (void)dealloc {

[[NSNotificationCenter defaultCenter] removeObserver:self]; // no need to call [super dealloc] here

}

Page 11: Lecture 3-ARC

ARC Rules (Contd.)• You cannot cast directly between id and void. This includes casting between

Foundation objects and Core Foundation objects.• You must use special casts, or calls to special functions, to tell the compiler more

information about the object's lifetime. Code example without ARC: - (NSString *)giveMeAString {

CFStringRef myString = [self someMethodThatCreatesACFString]; NSString *newString = (NSString *)myString; return [newString autorelease]; }

Code example with ARC and a cast: - (NSString *)giveMeAString { CFStringRef myString = [self someMethodThatCreatesACFString]; // retain count is 1 NSString *newString = (__bridge_transfer NSString *)myString; // the ownership has

now been transferred into ARC return newString; }

Page 12: Lecture 3-ARC

ARC Rules (Contd.)

• Code example with ARC and a function call:

- (NSString *)giveMeAString { CFStringRef myString = [self

someMethodThatCreatesACFString]; // retain count is 1 NSString *newString = (NSString

*)CFBridgingRelease(myString); // the ownership has now been transferred into ARC

return newString; }

Page 13: Lecture 3-ARC

ARC Rules (Contd.)• You cannot use NSAutoreleasePool objects.• You must use the @autoreleasepool syntax. This syntax is now available for

all Objective-C modes. Code example without ARC: - (void)loopThroughArray:(NSArray *)array {

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; for (id object in array) { // create a lot of temporary objects

} [pool drain]; } Code example with ARC: - (void)loopThroughArray:(NSArray *)array { - @autoreleasepool {

for (id object in array) {// create a lot of temporary objects } } }

Page 14: Lecture 3-ARC

ARC Rules (Contd.)

• You cannot call the functions NSAllocateObject and NSDeallocateObject• You cannot use object pointers in C structures (structs)• You cannot use memory zones (NSZone)• To properly cooperate with non-ARC code, you also cannot create a

method or a declared property (unless you explicitly choose a different getter) that begins with "copy".

Page 15: Lecture 3-ARC

Pointer Variables and Object Ownership

Pointer variables imply ownership of the objects that they point to.

• When a method (or function) has a local variable that points to an object, that variable is said to own the object being pointed to.

• When an object has an instance variable that points to another object, the object with the pointer is said to own the object being pointed to.

Page 16: Lecture 3-ARC

Pointer Variables and Object Ownership (Contd.)

• The idea of object ownership is useful for determining whether an object will be destroyed so that its memory can be reused. – An object with no owners will be destroyed. – An object with one or more owners will not be destroyed.

Page 17: Lecture 3-ARC

How objects lose owners

• A variable that points to the object is changed to point to another object. • A variable that points to the object is set to nil. • The owner of the object is itself destroyed. • The owner of the object is itself destroyed. An object in a collection, like

an array, is removed from that collection.

Page 18: Lecture 3-ARC

Ownership chains

• In main.m, after you finish printing out the array, you set the items variable to nil. Setting items to nil causes the array to lose its only owner, so the array is destroyed.

Page 19: Lecture 3-ARC

Ownership chains (Contd.)

• Let’s add some code so that you can see this destruction as it happens. • NSObject implements a dealloc method, which is sent to an object just

before it is destroyed. • You can override dealloc in BNRItem to print something to the console

when an item is destroyed.

- (void)dealloc { NSLog(@"Destroyed: %@", self); }

Page 20: Lecture 3-ARC

Strong Reference

• A strong reference (which you will use in most cases) means that you want to "own" the object you are referencing with this property/variable. The compiler will take care that any object that you assign to this property will not be destroyed as long as you (or any other object) points to it with a strong reference. Only once you set the property to nil then the object will get destroyed (unless one or more other objects also hold a strong reference to it).

• A strong reference cycle occurs when two or more objects have strong references to each other.

Page 21: Lecture 3-ARC

Step1: Add Strong Reference

• Let’s introduce a strong reference cycle in RandomItems to see how this works.

• First, you are going to give an instance of BNRItem the ability to hold another BNRItem (to represent something like a backpack or a purse). In addition, an item will know which other item holds it.

• In BNRItem.h, declare two instance variables and their accessors.

@interface BNRItem : NSObject { NSString *_itemName; NSString *_serialNumber; int _valueInDollars; NSDate *_dateCreated; BNRItem *_containedItem; BNRItem *_container; } + (instancetype)randomItem; - (instancetype)initWithItemName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber; -(instancetype)initWithItemName:(NSString *)name; - (void)setContainedItem:(BNRItem *)item; - (BNRItem *)containedItem; - (void)setContainer:(BNRItem *)item;

Page 22: Lecture 3-ARC

Step1: Add Strong Reference (Contd.)-(BNRItem *)container; In BNRItem.m, implement the accessors.

-(void)setContainedItem:(BNRItem *)item { _containedItem = item; // When given an item to contain, the contained item will be given a pointer to its container item.container = self; } - (BNRItem *)containedItem { return _containedItem; } - (void)setContainer:(BNRItem *)item { _container = item; } -(BNRItem *)container{ return _container; }In main.m, remove the code that populates the array with random items. Then create two new items, add them to the array, and make them point at each other.

Page 23: Lecture 3-ARC

Step1: Add Strong Reference (Contd.)

NSLog(@"Setting items to nil..."); items = nil; } return 0; } Here is what the application looks like now:

Page 24: Lecture 3-ARC

Memory Leak

• The two items cannot be accessed by any other part of the application (in this case, main()), yet they still exist, doing nothing useful. Moreover, because they cannot be destroyed, neither can the objects that their instance variables point to. So it will cause a Memory Leak in the application.

• To fix this problem, one of the pointers between the items needs to be a weak reference. To decide which one should be weak, think of the objects in the cycle as being in a parent-child relationship. In this relationship, the parent can own its child, but a child should never own its parent.

• In our strong reference cycle, the backpack is the parent, and the calculator is the child. Thus, the backpack can keep its strong reference to the calculator (the _containedItem instance variable), but the calculator’s reference to the backpack (the _container instance variable) should be weak.

Page 25: Lecture 3-ARC

Weak References

• With a weak reference you signify that you don't want to have control over the object's lifetime.

• The object you are referencing weakly only lives on because at least one other object holds a strong reference to it.

• Once that is no longer the case, the object gets destroyed and your weak property will automatically get set to nil.

• The most frequent use cases of weak references in iOS are: delegate properties, which are often referenced weakly to avoid retain cycles,

and subviews/controls of a view controller's main view because those views are

already strongly held by the main view.

Page 26: Lecture 3-ARC

Weak References (Contd.)

• Most strong reference cycles can be broken down into a parent-child relationship. A parent typically keeps a strong reference to its child, so if a child needs a pointer to its parent, that pointer must be a weak reference to avoid a strong reference cycle.

• A child holding a strong reference to its parent’s parent also causes a strong reference cycle. So the same rule applies in this situation: if a child needs a pointer to its parent’s parent (or its parent’s parent’s parent, etc.), then that pointer must be a weak reference.

• A weak reference knows when the object that it points to is destroyed and responds by setting itself to nil. Thus, if the backpack is destroyed, the calculator’s _container instance variable will be automatically set to nil. This is convenient. If _container was not set to nil, then destroying the object would leave you with a dangling pointer, which could crash your application.

Page 27: Lecture 3-ARC

Step-2: Add Weak Reference

• To declare a variable as a weak reference, you use the __weak attribute. In BNRItem.h, change the container instance variable to be a weak reference.

• __weak BNRItem *_container;

• Build and run the application again. This time, the objects are destroyed properly.

Page 28: Lecture 3-ARC

Step-2: Add Weak References (Contd.)

Page 29: Lecture 3-ARC

Properties

Without properties With properties

BNRThing.h

@interface BNRThing : NSObject { NSString *_name; } -(void)setName:(NSString *)n; -(NSString *)name; @end

@interface BNRThing : NSObject @property NSString *name; @end

BNRThing.m

@implementation BNRThing - (void)setName:(NSString *)n { _name = n; } -(NSString *)name { return _name; } @end

@implementation BNRThing @end

Page 30: Lecture 3-ARC

Step-3: Declare Properties

Page 31: Lecture 3-ARC

Step-3: Declare Properties (Contd.)

@property BNRItem *containedItem; @property BNRItem *container; @property NSString *itemName; @property NSString *serialNumber; @property int valueInDollars; @property NSDate *dateCreated; @end

Page 32: Lecture 3-ARC

Step-4: Delete Accessor Methods

Page 33: Lecture 3-ARC

ARC Variable Qualifier

• __strong• __weak• __unsafe_unretained• __autoreleasing

Page 34: Lecture 3-ARC

ARC Variable Qualifier (Contd.)

• __strong is the default. An object remains “alive” as long as there is a strong pointer to it.

• __weak specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong references to the object.

• __unsafe_unretained specifies a reference that does not keep the referenced object alive and is not set to nil when there are no strong references to the object. If the object it references is deallocated, the pointer is left dangling.

• __autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return.

Page 35: Lecture 3-ARC

ARC Property Attributes

• Retain• Assign• Unsafe_unretained• Copy• Strong• Weak• Readonly• Readwrite

Page 36: Lecture 3-ARC

ARC Property Attributes

• retain it says "keep this in the heap until I don't point to it anymore” In ARC it is used as strong Retain is the same as strong. Methods like "alloc" include an implicit "retain”

Example:@property (nonatomic, retain) NSString *name;

• assign

Exactly like weak except it doesn't nil out the object when released Use assign for C primitive properties and weak references to Objective-C objects.

Example:@property (nonatomic, assign) NSString *address;

Page 37: Lecture 3-ARC

ARC Property Attributes (Contd.)

• copy copy is required when the object is mutable. Returns a copy of the object

Example:@property (nonatomic, copy) NSArray *myArray;

• unsafe_unretained Doesn’t retain object like strong/retain attributes Does set to nil automatically like weak

Example:@property (nonatomic, unsafe_unretained) NSString *nickName;

Page 38: Lecture 3-ARC

ARC Property Attributes (Contd.)

• strong it says "keep this in the heap until I don't point to it anymore" Under ARC, strong is the default for object types. Retain is the same as strong.

Example:@property(strong) MyClass *myObject

• weak it says "keep this as long as someone else points to it strongly" Under ARC, strong is the default for object types. Retain is the same as strong.

Example:@property(weak) MyClass *myObject;

Page 39: Lecture 3-ARC

ARC Property Attributes (Contd.)

• readonly A readonly property just implements a getter. Can’t assign/change value

Example:@property (nonatomic, readonly) NSDate *dateCreated;

• readwrite Implements both getter and setter Can assign/change value

Example:@property (nonatomic, readwrite) NSDate *dateCreated;

Page 40: Lecture 3-ARC

Thread Management Property Attributes

• Nonautomic Nonatomic is thread unsafe. but it is fast in performance

Example:@property (nonatomic, retain) NSString *name;

• Automic It is used as default Atomic is thread safe. It is slow in performance

• Example:@property (retain) NSString *name;

Page 41: Lecture 3-ARC

Step-5: Add Nonautomic Attribute

• Unfortunately, the default value for this attribute is atomic, so you have to specify that you want your properties to be nonatomic.

@interface BNRItem : NSObject + (instancetype)randomItem; - (instancetype)initWithItemName:(NSString *)name valueInDollars:

(int)value serialNumber:(NSString *)sNumber; - (instancetype)initWithItemName:(NSString *)name;@property (nonatomic) BNRItem *containedItem; @property (nonatomic) BNRItem *container; @property (nonatomic) NSString *itemName;@property (nonatomic) NSString *serialNumber; @property (nonatomic) int valueInDollars; @property (nonatomic) NSDate *dateCreated; @end

Page 42: Lecture 3-ARC

Step-6: Add ReadOnly Attribute

• In BNRItem.h, declare dateCreated as a readonly property so that no setter method is generated for this instance variable.

@property (nonatomic, readonly) NSDate *dateCreated;

Page 43: Lecture 3-ARC

Step-7: Add Strong/Weak Attribute

• In BNRItem.m, set the memory management attribute as strong for the containedItem and dateCreated properties and weak for the container property.

@property (nonatomic, strong) BNRItem *containedItem; @property (nonatomic, weak) BNRItem *container; @property (nonatomic) NSString *itemName; @property (nonatomic) NSString *serialNumber; @property (nonatomic) int valueInDollars; @property (nonatomic, readonly, strong) NSDate *dateCreated;

• Setting the container property to weak prevents the strong reference cycle that you caused and fixed earlier.

Page 44: Lecture 3-ARC

Step-8: Add Copy Attribute

• In BNRItem.m, set the memory management attribute for itemName and serialNumber as copy.

@property (nonatomic, strong) BNRItem *containedItem; @property (nonatomic, weak) BNRItem *container; @property (nonatomic, copy) NSString *itemName; @property (nonatomic, copy) NSString *serialNumber; @property (nonatomic) int valueInDollars; @property (nonatomic, readonly, strong) NSDate *dateCreated;

• Here is what the generated setter for itemName will look like:

- (void)setItemName:(NSString *)itemName { _itemName = [itemName copy]; }

Page 45: Lecture 3-ARC

Step-9: Add Custom Accessor Property

• In BNRItem.m, add back an implementation for setContainedItem:.

- (void)setContainedItem:(BNRItem *)containedItem { _containedItem = containedItem; self.containedItem.container = self; }

Page 46: Lecture 3-ARC

Custom Accessors with Properties

• By default, the accessors that a property implements are very simple and look like this: - (void)setContainedItem:

(BNRItem *)item { _containedItem = item; } - (BNRItem *)containedItem

{ return _containedItem; }

• For most properties, this is exactly what you want. However, for the containedItem property, the default setter method is not sufficient.

• The implementation of setContainedItem: needs an extra step: it should also set the container property of the item being contained.

Page 47: Lecture 3-ARC

Custom Accessors with Properties (Contd.)

• When the compiler sees that you have implemented setContainedItem:, it will not create a default setter for containedItem. It will still create the getter method, containedItem.

• Note that if you implement both a custom setter and a custom getter (or just a custom getter on a read-only property), then the compiler will not create an instance variable for your property. If you need one, you must declare it yourself.

• Note the moral: sometimes the default accessors do not do what you need, and you will need to implement them yourself.

• Now you can build and run the application. The leaner BNRItem works in the exact same way.

Page 48: Lecture 3-ARC

Synthesize Property

@synthesize age = _age; // Other methods go here @end • This is how properties are automatically synthesized. The first attribute

(age) says “create methods named age and setAge:,” and the second attribute (_age) says “the instance variable that backs these methods should be _age.”

• You can optionally leave off the variable name, which creates a backing variable with the same name as the accessors. @synthesize age; // Is the same as: @synthesize age = age;

Page 49: Lecture 3-ARC

@autoreleasepool Directive

• With ARC, this is done automatically (and sometimes optimized out completely). An autorelease pool is created by the @autoreleasepool directive followed by curly braces.

• Inside those curly braces, any newly instantiated object returned from a method that does not have alloc or copy in its name is placed in that autorelease pool. When the curly brace closes, any object in the pool loses an owner. @autoreleasepool { // Get a BNRItem back from a method

that created it, method does not say alloc/copy BNRItem *item = [BNRItem someItem]; } // Pool is drained, item loses an owner and is destroyed

• iOS applications automatically create an autorelease pool for you, and you really do not have to concern yourself with it.

Page 50: Lecture 3-ARC

@autoreleasepool Directive (Contd.)

• Autorelease pool blocks provide a mechanism whereby you can relinquish ownership of an object, but avoid the possibility of it being deallocated immediately (such as when you return an object from a method).

• Typically, you don’t need to create your own autorelease pool blocks, but there are some situations in which either you must or it is beneficial to do so.