Some concepts of memory management
-
Why use memory management?
- Strict memory management can greatly improve the performance of our applications
- If memory management is ignored, the application may occupy too much memory, leading to program crash
-
There are three main methods of OC memory management:
- ARC (Automatic Memory Counting)
- Manual memory count
- Memory pool
-
The basic idea of MEMORY management in OC:
Make sure that at any time there are the same number of Pointers to an object as there are references to that object, so if you have one more pointer to that object, that object’s reference count goes up by one, and if you have one less pointer to that object, that object’s reference count goes down by one. There’s no pointer to this object and it gets released.
- Each object has a reference counter, and each new object has a counter of 1. When the object’s counter decreases to 0, it is destroyed
- Retain makes the object’s counter +1 and release makes the object’s counter -1
- Memory can also be managed through an Autorelease pool
- If ARC is used, the compiler automatically generates code to manage memory
-
Apple’s official basic memory management rules:
- You own whatever object you create
- You can use retain to obtain ownership of an object
- When you no longer need it, you must relinquish ownership of the object you own
- You must not release ownership of objects that you do not own
-
Any object that inherits NSObject is not valid for other non-object types (int, char, float, double, struct, enum, etc.)
-
OC objects are stored in the heap and non-OC objects are stored in the stack (stack memory is automatically reclaimed by the system).
Automatic memory management
-
When we compile source code, the compiler analyzes the life cycle of each object in the source code and then adds the corresponding reference counting operation code based on the life cycle of the object. So, ARC is a technical solution that works at compile time.
-
What is your understanding of ARC?
ARC
It’s a new feature in iOS 5. The compiler inserts them automatically in the appropriate places in the coderetain
/release
Complete memory management (reference counting). But the ARC compared with MRC, not add at compile time retain/release/autorelease so simple. Compile time and run time work together to help developers manage memory.- ARC is a compiler feature, not a runtime feature, nor is it a garbage collector in other programming languages. So automatic management is the same as manual memory management, but it is faster because the compiler performs some optimizations.
- RetainCount is used to determine if an object needs to be released. Every time the runloop is run, the object’s retainCount is checked. If the retainCount is 0, the object has no further use and can be released.
- At compile time, the ARC is more at the bottom of the C interface implementation retain/release/autorelease, do better, and why not in manual retain/release/autorelease ARC environment, Simultaneously optimizing pairs of retain/release operations on the same object in the same context (that is, ignoring unnecessary operations); ARC also includes run-time components, where optimization is more complex, but not negligible.
- ARC calls these methods not through objective-C’s message forwarding mechanism, but directly through the underlying C version of the API. This is better because the reserved and free operations need to be performed frequently, and calling the underlying functions directly saves CPU cycles. For example, ARC calls objc_retain, the underlying function equivalent to retain.
- When using ARC, you must follow the method naming rules, alloc, new, copy, mutablecopy. ARC standardizes memory management through naming conventions.
- ARC manages object lifetimes by inserting “save” and “release” operations where appropriate. Automatically insert a release into a method for objects created in the method; Class, which is released in the dealloc method.
- Under ARC, the memory management semantics of variables can be specified by modifiers.
- ARC only manages memory for Objective-C objects; CoreFoundation objects are not managed by ARC.
-
In ARC, what is the basis for the system to determine whether an object is destroyed? Whether there is a strong pointer to the object
-
Disabling ARC
Reference counter
How does the system determine when an object needs to be reclaimed? According to the object’s reference counter. You can also think of it as how many people are using this object.
- Sending a retain message to an object makes the reference counter +1(the retain method returns the object itself)
- Reference counter -1 by sending a release message to the object (note that release does not mean the object is destroyed/reclaimed, just counter -1)
- Send a retainCount message to the object to get the current reference count value
- When the reference counter of an object is 0, the memory occupied by the object is reclaimed by the system. The system automatically sends a dealloc message to the object
If the object’s counter is not zero, it cannot be reclaimed during the entire program’s run (unless the program exits).
dealloc
- Overriding the dealloc method overrides the dealloc method. In this case, MRC must call [super Dealloc] and call it last. [Super Dealloc] cannot be called from ARC. Dealloc cannot be called directly. Once the object is reclaimed, its memory is no longer available.
- Memory management for the dealloc method
- (void)dealloc {// Car release [_car release]; [super dealloc]; }Copy the code
Wild pointer \ null pointer
- Zombie object Objects that have been destroyed (objects that can no longer be used)
- Wild pointer
Pointer to zombie object (unavailable memory)
Sending a message to a wild pointer is reportedEXC_BAD_ACCESS
error - Null Pointers have no Pointers to storage (nil, 0). There is no response to sending a message to a null pointer
- A common way to avoid wild pointer errors is to make Pointers to objects null after they are destroyed
- Enable zombie object monitoring
By default, Xcode does not manage zombie objects and does not report errors using a free chunk of memory. To facilitate debugging, zombie object monitoring should be enabled
Automatic release tank
-
How to implement automatic release pool bottom layer? The memory in the stack has the stack, and the stack has the automatic release pool. Auto-release pool is implemented as a stack: when you create a new auto-release pool, it is added to the top of the stack. When an object receives a send autoRelease message, it is added to the autorelease pool at the top of the stack for the current thread. When the autorelease pool is reclaimed, they are removed from the stack and all objects in the pool are released.
As an iOS application runs, an infinite number of pools are created. These pools are stacked (first in, last out). When an object is called autoRelease, the object is placed in the release pool at the top of the stack
-
What is an automatic release pool? A: Automatic release pools are used to store pointer variables of multiple object types
-
What effect does auto-release pool have on objects in the pool? When the pool is destroyed, all objects in the pool will be released
-
How are objects put into the automatic release pool?
When you decide to put an object into the pool, you simply call the object’s autoRelease object method to put the object into the auto-release pool
-
What problems can result from multiple calls to an object’s autoRelease method? A: The IP address is saved to the automatic release pool for many times, causing an exception of the wild pointer
-
The autorelease pool function associates an object with an autorelease pool. The autorelease method is called in the pool to destroy the object at the time of autorelease pool destruction, delaying the release destruction time
-
Automatic release pool, when created?
- When the program starts, it also creates an automatic release pool
- After the event is generated, the automatic release pool is created when the running loop starts processing the event
-
When was it destroyed?
- Destroy before the end of the program
- After the event processing is complete, the automatic release pool is destroyed
- And when the pool is full, it’s destroyed
-
Note: Do not place a large number of loop operations under the release pool, as this will result in a large number of objects within the loop not being recycled, in which case you should write the release code manually. Try to avoid using autoreleases for large memory objects, as this will delay the collection of large memory.
-
How does apple implement autoreleasepool? Autoreleasepool is implemented as an array of queues. The following three functions form objc_autoreleasepoolPush, objc_autoreleasepoolPop, and objC_AutoRelease.
The first two perform push and POP operations on autoRelease, and destroy objects perform release. As an example, once a class is out of scope and a breakpoint is set in the class’s dealloc method, we can see this stack information.
-
When is an autoRelease object released? A: Autorelease actually just delays the call to Release. For each AutoRelease, the system simply puts the Object into the current Autoreleasepool. When the pool is released, All objects in the pool will be called Release. Autoreleasepool is implicitly created for each Runloop, so that all releasepool forms a stack structure like CallStack. At the end of each Runloop, the Autoreleasepool at the top of the stack is destroyed. So every Object in the pool (that’s an autoRelease Object) will be released. So what is a Runloop? A UI event, a Timer call, a delegate call, will be a new Runloop.
-
If we don’t create any autorelease pool in our application then is there any autorelease pool already provided to us? Automatic release pools are created and destroyed irregularly by default
-
When you will create an autorelease pool in your application? When you do not need to control exactly when an object is released, you can manually create an automatic release pool
@property Memory management policy selection
Read/write attributes: readwrite, readonly setter meaning: retain/copy Atomic, nonatomic strong/weak reference: strong, weak
-
Readwrite: generates both set and GET methods (default) Readonly: generates only GET methods
-
Control the memory management of the set method: retain: release old value, retain new value. When you want to take ownership of the source object, copy: release the old value and copy the new value for the other NSObject and its subclasses (for OC objects). If you want to obtain a copy of the source object without changing the content of the source object (usually used for NSString, block) assign: assign directly without any memory management (the default attribute). For base data types (NSInteger, CGFloat) and C data types (int, float, double, char, etc.)
-
Atomicity (multithreaded management) :
- Atomic default property. All access methods are atomic transaction access. The lock is added to the instance level of the owning object, and the performance is low. Atomicity means that an operation cannot be suspended by the CPU and then scheduled, that is, cannot be interrupted, either completed or not executed. If an operation is atomic, then in a multithreaded environment, there are no strange problems with variables being modified. Atomic operation is a non-separable operation. Atomic operation is a very important concept in multithreaded programs. It is often used to implement some synchronization mechanisms, and it is also the source of some common multithreaded bugs. Of course, atomic variables are less efficient to execute.
- nonatomic
Nonatomic access. Do not add synchronization, as far as possible to avoid multi-threading grab the same resource. The Value is directly fetched from the memory, because it is fetched from the memory, it does not have a lock protection for the CPU register to calculate the Value, it is simply used from the memory address, the current memory stored data results. Multi-threaded concurrent access improves performance, but does not guarantee data synchronization. Avoid multiple threads grabbing the same resource. Otherwise, the service logic of locking resource grabbing is handed over to the server to reduce the pressure on mobile clients.
OC can be used when multiple threads need to access the same data@synchronized
(variable) to lock the variable (often to synchronize or ensure atomic operations).
-
Strong, weak
strong
strong
The system generally does not automatically release inoc
In, objects default to strong Pointers. The reference is destroyed during scope destruction. In the actual open general property object generalstrong
To decorate (NSArray
.NSDictionary
Strong is also used when lazy loading is used to define controls.weak
weak
The counter of the referenced object is not incremented by one, and the pointer is automatically assigned to when the object is releasednil
, the system will immediately release the object.__unsafe_unretained
Weak reference The pointer is not automatically assigned to when an object is releasedni
Property modifiers are available in ARCassign
Be equivalent to__unsafe_unretained
)
Property modifiers are available in ARCretain
Be equivalent to__strong
)- Given that there are N Pointers to the same object, if at least one of them is a strong reference, the object will not be released as long as it is still in scope. Conversely, if all N Pointers are weak references, the object is immediately released
- In the use of
sb
orxib
When you drag a control line, why do you drag out the first property with the weak modifier?
Due to thexib
orsb
When a control is added inside, the subview is added to the following viewView
Up here, and the controllerController
To its root viewView
The default is strong reference when our child controls are added toview
Up there,self.view addSubView:
This method will strongly reference the added control if it is in usestrong
To modify the added child control, equivalent to two strong Pointers to the child control strong reference, in order to avoid this situation, so useweak
Modification.
Note:
(1) addSubView has a strong reference to its subView by default. (2) In the implementation of interface layout by pure hand code, if the interface control is processed through lazy loading, the use of strong pointer is required
-
Does ARC manage memory by assign or weak? Assign: If for some reason the proxy object is released, the proxy pointer becomes a wild pointer. Weak: If for some reason the proxy object is released, the proxy pointer becomes a null pointer, which is safer (weak cannot modify basic data types, only objects).
The use of the Copy
- Copy: creates immutable copies (such as NSString, NSArray, NSDictionary)
- MutableCopy: creates mutable copies (e.g. NSMutableString, NSMutableArray, NSMutableDictionary)
- Prerequisites for using copy
Copy: You need to comply with the NSCopying protocol to implement the copyWithZone: method@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end Copy the code
- MutableCopy: Complies with NSMutableCopying to implement the mutableCopyWithZone: method
@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end Copy the code
- Deep copy and Shallow Copy Deep copy (deep copy, content copy, deep copy)
- The source object and the replica object are two different objects
- The source object reference counter is unchanged, and the replica object counter is 1 (because it is newly generated)
- The essence is: new objects are created
Shallow copy (shallow copy, pointer copy, shallow copy)
- Source and replica objects are the same object
- The source object (replica object) references the counter + 1, which is equivalent to doing a retain operation
- The essence is: no new objects are created
- A shallow copy is a copy only if both the source object and the replica object are immutable. All other copies are deep copies
Memory analysis
- Static analysis
- Detection of potential memory problems in code without running the program (not necessarily 100% accurate, just suggestions)
- Combined with the actual situation to analyze, whether there is really a memory problem
- Dynamic analysis (Profile == Instruments)
- Run your program to look at memory Allocations, using app: You can see whether memory exploded or not after an action was made, such as a button \ indicating a controller
- Run the program and use the app to see if there are memory Leaks: the red area represents where memory Leaks occur
When do memory leaks and memory spills occur?
Memory leak: No longer used objects in the heap are not destroyed and still occupy memory. Memory overflow: A memory leak can be ignored, but too many memory leaks, memory will be occupied sooner or later, eventually resulting in memory overflow! When a program is applying for memory, there is not enough memory for it to use. For example, smaller data types store larger data.
- Memory leak check
About image memory management
-
Image loading memory comparison
- use
imageName:
Loading images:- After being loaded into the memory, the memory occupies a large space
- The same image, the image will not load twice
- Once loaded into memory, it stays in memory and will not be destroyed as the object is destroyed
- After loading in the image, the memory occupied by the system management, we can not manage
- use
imageWithContentsOfFile:
Loading pictures- After loading it into the memory, it occupies a small memory space
- The same image is repeatedly loaded into memory
- When objects are destroyed, images loaded into memory are destroyed along with them
- Conclusion:
- Pictures are small and used frequently
imageName:
To load (button icon/home page image) - The picture is larger and less used, using
imageWithContentsOfFile:
To load (version new features/albums)
- Pictures are small and used frequently
- use
-
The image’s presence in the sandbox
- For deployment versions >=iOS8, images from the packaged resource pack will be placed in Assets.car. Images are compressed; When deployed in
- Any Images that are not in images.xcassets are directly exposed in the main Bundle of the sandbox. Instead of being compressed into assets. car, they are placed in MainBudnle. The image is not compressed
- Conclusion:
- Small Images \ frequently used Images are placed inside images.xcassets
- Large Images \ Infrequently used Images (disposable Images, such as Images with new features) should not be placed inside images.xcassets
Memory management Problems
Single object memory management issues
- What are the main problems we’re working on with memory? Wild pointer: The object’s retainCount is 0, and the variable that holds the address of the object pointer is a wild pointer. Memory leak: an object that is no longer in use is not properly released and remains in memory
- Zombie objects? Objects with retainCount = 0 are called zombie objects, which are inaccessible
- What’s the problem with accessing zombie objects, sometimes right and sometimes wrong?
- How do I start Xcode’s zombie object detection feature?
- Can you call the retain method to revive an object when its retainCount = 0? Objects that have been released cannot be resurrected
- How do I prevent wild pointer operations? There are no null pointer exceptions in OC, so calling the method with [nil retain] will not result in an exception
- How many times can a memory leak happen?
- There is no paired release, which does not comply with memory management principles
- The object is pre-assigned to nil or cleared, causing the release method to not work
Multiple object memory management issues
- How many relationships exist between objects?
- Inheritance relationships
- Combination relationship
- Object is passed as a method parameter
- How do you ensure that an object that is a member variable in a combinatorial relationship of objects is not released prematurely? Override the set method, in which retain the object and increase its retainCount value by 1
- What are the causes of memory leaks caused by combinatorial relationships? In the set method, the object is retained, but no pairing is released
- Where should objects that are member variables be paired and released? Released in the dealloc function
Comparison of some data structures related to memory
-
This section describes memory partitions
- Code area: store function binary code
- Data area: memory is applied for and initialized when the system is running, and released by the system when the system exits. Store global variables, static variables, and constants
- Heap area: through malloc and other functions or operators such as new dynamic application to obtain, programmers need to manually apply and release
- Stack area: function module application, the end of the function by the system automatically released. Store local variables, function parameters
-
There are two types of storage space: RAM and Flash
- Memory is usually small: 1 GB, 2 GB, 3 GB, and 4 GB. Flash memory space is relatively large 16G, 32G, 64G;
- The read/write speed of memory is higher than that of flash memory.
- The things in the memory after the power is lost, the things in the flash memory power is not lost;
- Memory is the computer’s memory stick, flash memory is the computer’s hard drive;
-
What’s the difference between a heap and a stack?
- Management mode: Heap release work is controlled by programmers, easy to produce memory leak; The stack is managed automatically by the compiler without us having to manually control it.
- Application size: heap: A heap is a data structure that extends to a high address and is a discontinuous area of memory. This is because the system uses a linked list to store the free memory address, which is naturally discontinuous, and the traversal direction of the list is from low address to high address. The size of the heap is limited by the amount of virtual memory available in the computer system. Thus, the heap is more flexible and larger. Stack: Under Windows, a stack is a low-address data structure, a contiguous area of memory. The address at the top of the stack and the maximum size of the stack are specified by the system. Under Windows, the stack size is 2M (or 1M). If the stack size exceeds the available space, overflow will be prompted. Therefore, less space can be obtained from the stack.
- Fragmentation problem: heap: Frequent new/delete is bound to cause memory space discontinuity, resulting in a large amount of fragmentation, making the program inefficient. Stack: this problem does not exist, because stacks are first and last out queues, and they are so one-to-one that it is never possible for a block of memory to eject from the middle of the stack
- Allocation: The heap is dynamically allocated, there is no statically allocated heap. There are two types of stack allocation: static allocation and dynamic allocation. Static assignment is done by the compiler, such as assignment of local variables. Dynamic allocation is done by the alloc function, but stack dynamic allocation is different from heap dynamic allocation, which is released by the compiler without manual implementation.
- Allocation efficiency: stack: it is a data structure provided by the machine system, and the computer provides support for the stack at the bottom: special registers are allocated to store the address of the stack, and special instructions are executed to push and unload the stack, which determines the high efficiency of the stack. Heap: provided by C/C++ libraries, its mechanism is very complex.
- Each App has a memory space, say 4G, divided into two parts: heap and stack. Typically, each process has a heap (shared by all threads in the process), and the threads in the process have their own stack. Memory obtained by alloc, new, or malloc is allocated in the heap, and memory in the heap needs to be freed by writing the corresponding code. Memory allocated in the heap is automatically freed if the process terminates. Local variables and function parameters are allocated in stack space. If the function returns the memory occupied by the local variables and function parameters in the function, the system automatically frees (reclaim). The program allocates memory for variables and functions on the stack at compile time, and the parameters of function calls are passed on the stack during program execution.
-
What’s the difference between a queue and a stack: A queue and a stack are two different data containers. From the point of view of “data structures,” they are linear structures, meaning that the relationships between data elements are the same. A queue is a first-in, first-out (FIFO) data structure that operates at both ends, with enqueueing at one end and queuing at the other. The stack is a kind of data structure, which can only operate at the top of the stack, and both loading and unloading operate at the top of the stack.
-
What’s the difference between a list and an array? Both belong to the same data structure. If you want to access data quickly, with little or no insert and delete elements, use arrays. In contrast, linked list data structures are used if you need to insert and delete elements frequently.
- In terms of logical structure
- Arrays must have a fixed length (the number of elements) defined in advance, and cannot be used to dynamically increase or decrease data. As the data increases, the number of elements may exceed the original definition; When data is reduced, memory is wasted; Arrays can be accessed directly by subscript.
- Linked list can dynamically allocate storage, adapt to the situation of dynamic increase and decrease of data, and can easily insert and delete data items. The list must find the next element based on the next pointer
- In terms of memory storage
- Arrays allocate space from the stack, which is fast and convenient for programmers, but has little freedom
- Linked lists allocate space from the heap, which has a lot of freedom but is cumbersome to manage
- In terms of logical structure
The interview questions
-
How can I minimize memory leaks in my program
- The ARC
Foundation
Object (OC
Object) : as long as the method containsalloc\new\copy\mutableCopy\retain
And so on, then the object produced by these methods must be called once when it is no longer in userelease
Or 1 timeautorelease
.
CoreFoundation
Object (C
Object) : as long as the function containscreate\new\copy\retain
And so on, then the object produced by these methods must be called once when it is no longer in useCFRelease
Or otherrelease
Function. - ARC(Only OC objects are automatically managed, C objects are not automatically managed)
CoreFoundation
Object (C
Object) : as long as the function containscreate\new\copy\retain
And so on, then the object produced by these methods must be called once when it is no longer in useCFRelease
Or otherrelease
Function.
- The ARC
-
The attention of the block
Void (^test)() = ^{}; Block_copy(test); // If a block is copied, its memory is moved to the heap (code management is required) Block_copy(test); Block_release(test); Block_release(test); [test release];Copy the code
-
Unreferenced the Block loop
-
The wild pointer example creates a view controller (ARC) and writes the following code in a function. When this function returns, b will be freed because there is no pointer to b, but B. View will not be freed. If there is something in B that needs to be done on B (such as a proxy method), wild Pointers will be generated.
B *b = [[B alloc]init]; [self.view addSubview:b.view]; Copy the code
-
Set method
- How many situations can cause a memory leak in a combinatorial relationship of objects? 1. No retain object in set method 2. No release of old object 3 Does not determine whether the same object is passed into the set method
- How do I properly override the set method?
Retain the new object write a setter to do @property (nonatomic,retain) NSString *name, So let’s write a setter method to do @property (nonatomic, copy) NSString *name. “` @property (nonatomic, retain) NSString *name; – (void)setName:(NSString *)name { if (_name ! = name) { [_name release]; _name = [name retain]; }}
@property(nonatomic, copy) NSString *name; - (void)setName:(NSString *)name { if (_name ! = name) { [_name release]; _name = [name copy]; } } - (void)dealloc { self.name = nil; [_name release]; _name = nil; } ` ` `Copy the code
-
Use of reference counting
int main(int argc, const char * argv[]) { @autoreleasepool { // 1 Person *p = [[Person alloc] init]; p.age = 20; // p is a pointer to a zombie object (bad memory) [p release]; // p is called null pointer p = nil; p.age = 40; // [0 setAge:40]; // Message sent to deallocated instance 0x100201950 [p release]; } return 0; }Copy the code
Stack and heap
#import <Foundation/Foundation.h> #import "Car.h" int main(int argc, const char * argv[]) { @autoreleasepool { int a = 10; // stack int b = 20; // stack // c: stack // Car (counter ==1) : heap Car *c = [[Car alloc] init]; } // When autoreleasepool is finished, all variables in the stack (a, b, c) will be recycled, but the Car object in the heap will remain in memory, because it is still 1; return 0; }Copy the code
-
If I look at the following program, what does NSLog output three times? Why is that? Results: 3, 2, 1
NSMutableArray* ary = [[NSMutableArray array] retain]; NSString *str = [NSString stringWithFormat:@"test"]; // 1 [str retain]; // 2 [ary addObject:str]; // 3 NSLog(@"%d", [str retainCount]); [str retain]; // 4 [str release]; // 3 [str release]; // 2 NSLog(@"%d", [str retainCount]); [ary removeAllObjects]; // 1 NSLog(@"%d", [str retainCount]); Copy the code
-
MRC reference count of copy retain retain
- (void)setName:(NSString *)name{ if (_name ! = name) { [ _name release]; _name = [name retain]; } } - (NSString *)name{ return [[ _name retain] autorelease]; }Copy the code
copy
- (void)setName:(NSString *)name{ if (_name ! = name) { [ _name release]; _name = [name copy]; } } - (NSString *)name{ return [[ _name retain] autorelease]; }Copy the code
NSString copy is a shallow copy, a pointer copy, and the reference count +1 is the same as retain. Shallow replication is pointer replication. There are two Pointers, one address space, and the old pointer and the copy pointer point to the same address space. If the source address data changes, the two Pointers point to a different value. For non-container objects in the system, copy is a pointer copy (shallow copy) and mutbleCopy (deep copy) of an immutable object. For mutable objects, both are deep copies, but the object returned by copy is immutable. That’s at sign property (copy) NSString *name; The name pointer is copied. Two different Pointers. If one is assigned to another value, the name does not change. We start with two Pointers to the same address, and if the address changes, both of them change.
-
[NSArray arrayWithobject:] Do I need to free this array? A: No, this object is put into the auto release pool
-
Older versions of projects are projects that can be converted to use ARC. The conversion rules include:
- Remove all retain, release, autorelease
- Replace NSAutoRelease with the @Autoreleasepool {} block
- Change the assign attribute to weak using some of the ARC enforcement rules
- The dealloc method is used to manage some resources, but cannot be used to release instance variables, nor can the super dealloc method be removed from the dealloc method. Under ARC, the parent class dealloc is also done automatically by the compiler
- Core Foundation objects can still use methods like CFRetain and CFRelease
- You cannot use NSAllocateObject and NSDeallocateObject anymore
- Object Pointers cannot be used in C structures, but you can create an Objective-C class to manage these objects if you have similar functionality
- There is no easy way to convert between ID and void *, and conversions between Objective-C and Core Foundation types require compiler-specified conversions
- Memory stores cannot be used (NSZone can no longer be used)
- You cannot name an attribute starting with new
- You should always use weak when you declare outlets, except for storyboards, so the top level object in the middle of the NIB should be strong
- Weak corresponds to the old version of assign, and strong corresponds to retain