IOS uses ARC to manage memory (content is programmed based on iOS) and iosarc
When a program executes a method (or function ),StackThe Region allocates a piece of memory space, which is calledFrame. Frame is the value of the variable declared by the Protection Program in the method. The variables declared in the method are calledLocal variable.
When our program starts, as the program entryMainFunction, and its frames will be saved on the stack. When main calls another method, this method is pushed to the top of the stack. The called method also calls other methods, so that the call will form a frame sequence. When the execution of the called method ends, the program will remove its frame from the top of the stack."Pop-up"And release the Response Memory.
Therefore, the stack memory format isAdvanced and later.
The heap is another area in the value memory, which is separated from the stack. The heap contains a large number of unordered active objects. You need to use pointers to save the addresses of these objects in the heap. When an application sends an alloc message to a class, the system allocates a block of memory from the heap, which is the size of all instance variables of the object.
When the iOS app starts and runs, it will continuously create the required objects. If the heap space is unlimited, you can create the required objects at will. But unfortunately, the memory space at our disposal of available applications is very limited. Therefore, when an application no longer needs some objects, it must be released. The released object can return the memory it occupies to the heap for reuse. In the end, we need to avoid releasing the objects in use by the application at any time.
- Pointer variables and object ownership
The pointer variable impliesOwnership.
Which of the following situations causes the object to lose its owner?
- Strong reference and weak reference
As long as the pointer variable points to an object, the corresponding object will have one more owner and will not be released by the program. This pointer feature is calledStrong reference.
The program can also choose to make the pointer variable do not affect the number of owners pointing to the object. This pointer feature does not change the number of object owners is calledWeak references.
Weak references are very suitable for solvingStrong reference LoopMemory management issues. When two or more objects are correlated with pointers with strong reference characteristics, a strongly referenced loop is generated. This loop will cause memory leakage. In this loop, the program cannot release the memory through the ARC mechanism.
Add a strong reference loop in RandomItems to explain how to solve such problems.
# Import <Foundation/Foundation. h> @ interface JXItem: NSObject {NSString * _ itemName; NSString * _ serialNumber; int _ valueInDollars; NSDate * _ dateCreated;// Add here so that the JXItem object can save another JXItem object. JXItem * _ containedItem; JXItem *_ Container;} // Initialization method-(instancetype) initWithItemName :( NSString *) name valueInDollars :( int) value serialNumber :( NSString *) sNumber;-(instancetype) initWithItemName :( NSString *) name;-(Void) setContainedItem :( JXItem *) item;-(JXItem *) containedItem;-(void) setContainer :( JXItem *) item;-(JXItem *) container;// Save method-(void) setItemName :( NSString *) str; // obtain method-(NSString *) itemName;-(void) setSerialNumber :( NSString *) str; -(NSString *) serialNumber;-(void) setValueInDollars :( int) v;-(int) valueInDollars;-(NSDate *) dateCreated; @ end
Implementation Method:
# Import "JXItem. h "@ implementation JXItem-(instancetype) initWithItemName :( NSString *) name valueInDollars :( int) value serialNumber :( NSString *) sNumber {// call the parent class's initialization method self = [super init]; // determine whether the specified Initialization Method of the parent class is successfully created if (self) {// set the initial value _ itemName = name; _ serialNumber = sNumber; _ valueInDollars = value for the instance variable; // set the value of _ dateCreated to the current system time // because we have not set the set Method for the instance variable to obtain it from the outside (only a read-only attribute) _ dateCreated = [NSDate date];} // return the new address of the initialized object return self ;}-(Void) setContainedItem :( JXItem *) item {_ containedItem = item; // when an item is added to a JXItem object containing it, it directs its container instance variable to the object item that holds it. container = self;}-(JXItem *) containedItem {return _ containedItem;}-(void) setContainer :( JXItem *) item {_ container = item;}-(JXItem *) container {return _ container ;}-(Instancetype) initWithItemName :( NSString *) name {return [self initWithItemName: name valueInDollars: 0 serialNumber: @ ""] ;}// default initialization method, call the custom initialization method and enter the default value-(instancetype) init {return [self initWithItemName: @ "Item"];}-(void) setItemName :( NSString *) str {_ itemName = str;}-(NSString *) itemName {return _ itemName;}-(void) setSerialNumber :( NSString *) str {_ serialNumber = str ;} -(NSString *) serialNumber {return _ serialNumber;}-(void) setValueInDollars :( int) v {_ valueInDollars = v;}-(int) valueInDollars {return _ valueInDollars ;} -(NSDate *) dateCreated {return _ dateCreated;}-(NSString *) description {NSString * descriptionString = [[NSString alloc] initWithFormat: @ "% @ (% @): worth $ % d, recorded on % @ ", self. itemName, self. serialNumber, self. valueInDollars, self. dateCreated]; return descriptionString;} @ end
Implementation Method in main. m
# Import <Foundation/Foundation. h> # import "JXItem. h "int main (int argc, const char * argv []) {@ autoreleasepool {// create an NSMutableArray object, use the items variable to save the object address NSMutableArray * items = [[NSMutableArray alloc] init];JXItem* Backpack = [[JXItem alloc] initWithItemName: @ "Backpack"]; [items addObject: backpack]; JXItem * calculator = [[JXItem alloc] initWithItemName: @ "Calculator"]; [items addObject: calculator]; backpack. containedItem = calculator; backpack = nil; calculator = nil;// Use the quick enumeration method to traverse for (NSString * item in items) {NSLog (@ "% @", item) ;}} return 0 ;}
Print result:
2016-09-09 00:47:04.537 RandomItems[27531:2815858] Backpack (): Worth $0,recorded on 2016-09-08 16:47:04 +00002016-09-09 00:47:04.537 RandomItems[27531:2815858] Calculator (): Worth $0,recorded on 2016-09-08 16:47:04 +0000Program ended with exit code: 0
The release information is not printed. We can understand this as follows: When backpack. containedItem = calculator is executed, the set Method in JXItem is actually executed. That is, [backpack setContainer: calculator]; we can view our custom methods in the class. We can see that backpack is self at this time, and self has a pointer to calculator, that is, the owner of calculator. At the same time, in the implementation method, item. container = self; at this time, the item is calculator, and all causesLoop reference.
To solve this type of circular reference problem, we need to change any pointer between the newly created two objects to the weak reference feature. Before deciding which pointer to change to a weak reference, we can determine the response parent-child relationship for multiple objects with strong reference loops. We can make the parent object have sub-objects and ensure that the sub-objects do not have the parent object. The format is _ weak JXItem * _ container;
Attribute is used to simplify the declaration of variables and storage methods. Declaration method: @ property NSString * itemName;
# Import <Foundation/Foundation. h> @ interface JXItem: NSObject@ Property NSString* ItemName; @ property NSString * serialNumber; @ property int valueInDollars; @ property NSDate * dateCreated; @ property JXItem * containedItem; @ property JXItem * container;// Initialization method-(instancetype) initWithItemName :( NSString *) name valueInDollars :( int) value serialNumber :( NSString *) sNumber;-(instancetype) initWithItemName :( NSString *) name; -(void) setContainedItem :( JXItem *) item;-(JXItem *) containedItem;-(void) setContainer :( JXItem *) item;-(JXItem *) container; // save method-(void) setItemName :( NSString *) str; // obtain method-(NSString *) itemName;-(void) setSerialNumber :( NSString *) str; -(NSString *) serialNumber;-(void) setValueInDollars :( int) v;-(int) valueInDollars;-(NSDate *) dateCreated; @ end
Implementation Method: the attribute name is the name of the instance variable, removing the underline. the compiler will automatically underline the variable name when generating the instance variable according to the attribute, the corresponding access method can also be automatically generated.
# Import "JXItem. h "@ implementation JXItem-(instancetype) initWithItemName :( NSString *) name valueInDollars :( int) value serialNumber :( NSString *) sNumber {// call the parent class's initialization method self = [super init]; // determine whether the specified Initialization Method of the parent class is successfully created if (self) {// set the initial value _ itemName = name; _ serialNumber = sNumber; _ valueInDollars = value for the instance variable; // set the value of _ dateCreated to the current system time // because we have not set the set Method for the instance variable to obtain it from the outside (only a read-only attribute) _ dateCreated = [NSDate date];} // return the new address of the initialized object return self;}-(void) setContainedItem :( JXItem *) item {_ containedItem = item; // when an item is added to a JXItem object that contains it, its container instance variable is directed to the object item that contains it. container = self;}-(JXItem *) containedItem {return _ containedItem;}-(void) setContainer :( JXItem *) item {_ container = item;}-(JXItem *) container {return _ container;}-(instancetype) initWithItemName :( NSString *) name {return [self initWithItemName: name valueInDollars: 0 serialNumber: @ ""];} // The default initialization method. Call the custom initialization method and enter the default value-(instancetype) init {return [self initWithItemName: @ "Item"];} -(void) setItemName :( NSString *) str {_ itemName = str;}-(NSString *) itemName {return _ itemName;}-(void) setSerialNumber :( NSString *) str {_ serialNumber = str;}-(NSString *) serialNumber {return _ serialNumber;}-(void) setValueInDollars :( int) v {_ valueInDollars = v;}-(int) valueInDollars {return _ valueInDollars;}-(NSDate *) dateCreated {return _ dateCreated;}-(NSString *) description {NSString * descriptionString = [[NSString alloc] initWithFormat: @ "% @ (% @): Worth $ % d, recorded on % @", self. itemName, self. serialNumber, self. valueInDollars, self. dateCreated]; return descriptionString;} @ end
Attribute features
Any attribute can have a set of features used to describe the behavior of an access method. These features need to be written in parentheses and followed by the @ property command. For example, @ property (nonatomic, copy) NSString * itemName; Any attribute has three features, each of which has multiple optional types.
Attribute features-multithreading features
This feature has two optional types: nonatomic and atomic. The former is non-atomic access and does not apply thread locks. The latter is the opposite. However, although the thread locks are absolutely safe, they are inefficient and are generally not recommended. The default value is atomic access.
# Import <Foundation/Foundation. h> @ interface JXItem: NSObject@ Property (nonatomic) NSString* ItemName; @ property (nonatomic) NSString * serialNumber; @ property (nonatomic) int valueInDollars; @ property (nonatomic) NSDate * dateCreated; @ property (nonatomic) JXItem * containedItem; @ property (nonatomic) JXItem * container;// Initialization method-(instancetype) initWithItemName :( NSString *) name valueInDollars :( int) value serialNumber :( NSString *) sNumber;-(instancetype) initWithItemName :( NSString *) name; @ end
Attribute features-read/write features
This feature also has two optional types: readwrite and readonly. By default, the compiler generates an access method based on the attributes of the readwrite feature. However, for the readonly attribute, only the method is generated.
# Import <Foundation/Foundation. h> @ interface JXItem: NSObject @ property (nonatomic) NSString * itemName; @ property (nonatomic) NSString * serialNumber; @ property (nonatomic) int valueInDollars;@ Property (nonatomic,Readonly) NSDate *DateCreated;@ Property (nonatomic) JXItem * containedItem; @ property (nonatomic) JXItem * container; // initialization method-(instancetype) initWithItemName :( NSString *) name valueInDollars :( int) value serialNumber :( NSString *) sNumber;-(instancetype) initWithItemName :( NSString *) name; @ end
Attribute features-memory management features
This feature has four optional types: strong (default attribute), weak, copy, unsafe_unretained. For attributes that do not point to any object, that is, the basic data type, we do not need to perform memory management. At this time, we should choose unsafe_unretained, which means that the access method will directly assign values to the instance variables. InARCPreviously, we used assign. Now we can still use this attribute.
Generally, a property is a pointer to another object, and the class of this property has a modifiable subclass (NSString/NSMutableString, NSArray/NSMutableArray) in this case, we should set its attribute memory management to copy.
# Import <Foundation/Foundation. h> @ interface JXItem: NSObject @ property (nonatomic,Copy) NSString * itemName; @ property (nonatomic,Copy) NSString * serialNumber; @ property (nonatomic) int valueInDollars; @ property (nonatomic, readonly,Strong) NSDate * dateCreated; @ property (nonatomic,Strong) JXItem * containedItem; @ property (nonatomic,Weak) JXItem * container; // initialization method-(instancetype) initWithItemName :( NSString *) name valueInDollars :( int) value serialNumber :( NSString *) sNumber;-(instancetype) initWithItemName :( NSString *) name; @ end
After being changed to the copy feature, the property storage method may be similar to the following code:
- (void)setItemName:(NSString *)itemName { _itemName = [itemName copy];}
This Code does not include the passed ValueItemNameAssign values directly to instance variables_ ItemNameInsteadItemNameSentCopyInformation. TheCopyMethod returns a new NSString object. The reason for this is: if the class of the object to which the attribute points has a modifiable subclass, the attribute may point to the modifiable subclass object. At the same time, this object may be modified by another owner. Therefore, we recommend that you copy the object before directing the property to the Copied object. HoweverCopyIn the method, the NSString object will not change, so we generally only set the variable object to copy, copying an immutable object is a waste of space.
Access Method for Custom Attributes
By default, an access method is automatically generated, which is very simple;
- (void)setContainedItem:(JXItem *)item { _containedItem = item;}- (JXItem *)containedItem { return _containedItem;}
We can use the access methods added by custom attributes directly, and we can also customize the access methods. After the custom access methods, the compiler will not create a default access method for us.
- (void)setContainedItem:(JXItem *)containedItem { _containedItem = containedItem; self.containedItem.container = self;}