UIView
andCALayer
What is the relationship?
UIView
Inherited fromUIResponder
Class that can respond to eventsCALayer
Directly inherited fromNSObject
Class that cannot respond to eventsUIView
isCALayer
thedelegate
(CALayerDelegate
)UIView
Primarily dealing with events,CALayer
Responsible for the drawing- each
UIView
There’s one on the insideCALayer
Provide the content behind the drawing and display, andUIView
The dimensions and styles are all made up of internalLayer
Provided. Both have tree-like hierarchies,Layer
internalSubLayers
.View
internalSubViews
, butLayer
thanView
More than aAnchorPoint
NSCache
andNSMutableDictionary
Similarities and differences
Similarities: NSCache and NSMutableDictionary functions are basically the same differences: NSCache is thread-safe, NSMutableDictionary threads are not, A class developed by Mutable is generally not thread-safe. NSCache automatically frees memory when it runs out of memory (so always check for empty data when fetching from the cache). NSCache can specify a cache limit, The NSCache Key is a Strong reference to the object, not a copy, so NSCopying is not required
atomic
The implementation mechanism of the; Why can’t absolute thread-safety be guaranteed (preferably in context)
atomic
It’s going to be on the propertysetter/getter
Method to lock, which is only guaranteed during operationsetter/getter
The method is safe. The safety of other threads cannot be guaranteed- For example, thread 1 called the property of
setter
Method and thread 2 calls it halfway throughgetter
Method, then the execution will finishsetter
After the operation, run the command againgetter
Operation, thread 2 gets thread 1setter
After the full value; When several threads simultaneously invoke the same attributeSetter and getter
Method, a complete value is obtained, but the value obtained is not controllable
- Several methods of introspection in iOS
The ability of an object to get its type at run time is called introspection. Introspection there are several ways to implement introspection at OC runtime:
- Determine the object type:
-(BOOL) isKindOfClass: // Check whether it is an instance of this class or a subclass of this class -(BOOL) isMemberOfClass: // Check whether it is an instance of this classCopy the code
- Determines whether an object/class has this method
- (BOOL) respondsToSelector: / / instance such method + (BOOL) instancesRespondToSelector: / / judge whether there is the wayCopy the code
objc
What happens when you send a message to an object
Find the class of the object based on its ISA pointer, and go to objc’s corresponding class to find method 1. First, look for the invoked method in the list of cached methods in the object of the corresponding operation. If found, turn to the corresponding implementation and execute 2. If no, look for the called method in the method list of the corresponding operation object. If no, go to the corresponding implementation and perform 3. If not, go to the object pointed to by the parent pointer and execute 1,2. 4. And so on. An error is reported if the intercepting method was not overridden
- Have you ever been exposed to the reflex mechanism in OC? Talk a little bit about the concept and usage
class
reflection- Instantiate an object as a string of class names
Class class = NSClassFromString(@"student");
Student *stu = [[class alloc] init];
Copy the code
- Change the class name to a string
Class class = [Student class];
NSString *className = NSStringFromClass(class);
Copy the code
SEL
The reflection of- Instantiate a method as a string
SEL selector = NSSelectorFromString(@"setName");
[stu performSelector:selector withObject:@"Mike"];
Copy the code
- Turn the method into a string
NSStringFromSelector(@selector(setName:));
- What could go wrong with this notation
@property (nonatomic, copy) NSMutableArray *arr;
When adding, deleting, or modifying elements in an array, the program will crash because it can’t find the corresponding method. Cause: Copy copies an immutable NSArray object. You cannot add or modify an NSArray object
- How do I make my classes useful
copy
The modifier
If you want to copy your own objects, you need to implement the NSCopying protocol. NSCopying and NSMutableCopying protocols are implemented simultaneously if the custom object is of mutable and immutable versions. 1. Declare that the class complies with the NSCopying protocol. 2
NSCopying
Protocol method:
- (id)copyWithZone:(NSZone *)zone {
MyObject *copy = [[[self class] allocWithZone: zone] init];
copy.username = self.username;
return copy;
}
Copy the code
- why
assign
Cannot be used to modify objects
First of all, we need to be clear that the memory of the object is usually allocated to the heap, and the memory of the basic and OC data types is usually allocated to the stack. If we assign the object, when the object is released, the address of the pointer still exists, which means that the pointer is not set to nil, thus creating a wild pointer. Because objects are allocated on the heap, memory on the heap is allocated and freed by the programmer. And because Pointers aren’t set to nil, if a subsequent allocation happens to be in this block, it’s going to crash and assign decorates the base data type or the OC data type, because the base data type is allocated on the stack, allocated and freed by the system, so it’s not going to cause wild Pointers
- Write the following code output
int a[5] = {1, 2, 3, 4, 5};
int *ptr = (int *)(&a + 1);
printf("%d, %d", *(a + 1), *(ptr + 1));
Copy the code
Random value analysis: a represents the first address of an array with five elements, and the elements of a[5] are 1,2,3,4,5. Next, a + 1 means the beginning of the data plus 1, so it’s a[1], which corresponds to a value of 2, but it’s ampersand a + 1, because a is the entire array, and it’s 5 times sizeof(int), so ampersand a + 1 is a + 5. A is a constant pointer to the beginning of the current array, and the pointer +1 moves sizeof(int) by a number of bytes. So PTR is a pointer to int *, and PTR is a pointer to a + 5, so PTR +1 is also a + 6, so the last *(PTR +1) is a random value. And *(PTR – 1) is the same thing as a plus 4, which is equal to 5
- a
view
It’s already initialized,view
I added n to itbutton
(may be created using a loop), exceptview
thetag
What else can you do to find what you wantbutton
To modify theButton
The value of the
If a button is clicked, it will refresh its value, other need not modify, then do not reference any button, directly in the callback, has already received the response button to pass, directly through it can modify the second type: When a button is clicked, all buttons of the same type change their values, so you can create the button by storing it in an array and iterating through it as needed
UIViewController
theViewDidUnload, viewDidLoad
andloadView
When are they called?UIView
thedrawRect
andlayoutSubviews
What do they do
First question: viewDidUnload is called before the controller is destroyed, loadView is called when the controller doesn’t have any views and viewDidLoad is called when the view is finished loading. Second question: After we call setNeedsDisplay, we’ll call drawRect, and we can do that by getting the context and then setNeedsLayout, we’ll call layoutSubviews, We can tweak the UI in this way. Of course, there are many ways to cause layoutSubviews to be called, such as adding subviews, scrolling scrollViews, changing the view’s frame, etc
- Working principle of automatic release pool
An autorelease pool is an instance of the NSAutorelease class. When an autoRelease message is sent to an object, the object is automatically pooled, and when the pool is destroyed, a release message is sent to all objects in the pool. The release object [Pool Release], [pool drain] means that the pool itself is not destroyed, but that temporary objects in the pool are sent releases to destroy the object
- How does Apple do that
autoreleasepool
the
Autoreleasepool is implemented by AutoreleasePoolPage as a bidirectional list through the following three functions:
- by
objc_autoreleasePoolPush
As the first function to automatically release the pool scope- use
objc_autorelease
Adds objects to the automatic release pool- by
objc_autoreleasePoolPop
As the last function to automatically release the pool scope
autorelease
When the object is released
RunLoop goes to the auto-free pool at the end of each event loop to reduce the reference count of all auto-free objects by one. If the reference count becomes zero, the object is actually destroyed and memory is reclaimed. Without manually adding an Autorelease Pool, the Autorelease Pool will reduce the reference count of all autoreleased objects by one at the end of each event loop. If the reference count becomes zero, the object will be freed and memory will be reclaimed. Therefore, if you want torelease an AutoRelease object earlier, you can add an automatic release pool to the object. For example, when looping through data, temporary variables should be released quickly:
// Add @autoreleasepool directly to objects created by alloc. Autorelease is not required for objects created by class methods. The reason is that the system automatically adds autoReleases to objects created by class methodsfor (int i = 0; i < 1000000; i++) {
@autoreleasepool {
NSString *str = @"Abc";
str = [str lowercaseString];
str = [str stringByAppendingString:@"xyz"];
NSLog(@"% @", str); } // From here, the automatic release pool will be traversed.Copy the code
- This section describes basic principles of memory management
OC memory management follows the mechanics of who creates, who frees, who references, and who manages. When you use alloc, copy, or retian an object, you’re obligated to send a release or autoRelease message to it torelease the object. You don’t need to manage memory. When the object reference count reaches zero, the system will release the object. This is the OC’s manual management mechanism (MRC) that sends an AutoRelease message to an object. It releases the object by sending a release message to every object in the pool, not because the object is destroyed, but when the object’s reference count reaches zero, the system calls the dealloc method to release the object and its own instances
sizeof
The keyword
Sizeof is processed at compile time and cannot be compiled to machine code. The result of sizeof is equal to the number of bytes of memory occupied by the object or type. Sizeof returns a value of type size_t variable: int a; Sizeof (a) is 4; Pointer: int *p; Sizeof (p) is 4; Array: int b[10]; Sizeof (b) is the sizeof the array 4*10; int c[0]; Sizeof c is equal to 0, sizeof void is equal to 1, sizeof void star is equal to 4
- What is off-screen rendering? Under what circumstances can it be triggered? Off-screen rendering is a performance drain
Off-screen rendering is to create a new buffer outside the current screen buffer for operation. Off-screen rendering triggers the following scenes:
- Rounded corners (set at the same time
Layer. masksToBounds = YES, layer.cornerRadius
Greater than zero)- Layer mask
- The shadow,
layer.shadowXXX
If setlayer.shadowPath
There will be no off-screen rendering- Mask,
layer.mask
- Rasterizer,
layer.shouldRasterize = YES
The reason why off-screen rendering consumes performance is that it needs to create a new buffer. In the whole process of off-screen rendering, it needs to switch the context environment several times. First, it needs to switch from the current Screen to the off-screen and display the rendering result of the off-screen buffer On the Screen after the off-screen rendering is finished. You also need to switch the context from off-screen to the current screen
- In ARC, what are the default keys when you do not explicitly specify any property keys
The default keywords for basic data types are: atomic, readwrite, assign The default keywords for ordinary Objective-C objects are: atomic, readwrite, strong
- What are the essential differences and connections between class methods and instance methods in OC
Methods:
- Class methods belong to class objects
- Class methods can only be called from class objects
- Self in the class method is the class object
- Class methods can call other class methods
- A member variable cannot be accessed in a class method
- Object methods cannot be called directly from a class method
Instance methods:
- Instance methods belong to instance objects
- Instance methods can only be called from instance objects
- Self in the instance method is the instance object
- Member variables can be accessed in instance methods
- Instance methods are called directly from instance methods
- Class methods can also be called from instance methods (by class name)
- Can I add instance variables to the compiled class? Can I add instance variables to classes created at run time? Why is that?
- You cannot add instance variables to compiled classes
- Ability to add instance variables to classes created at run time
- Because the compiled classes are already registered in
runtime
In the class structureobjc_ivar_list
The linked list sum of instance variablesinstance_size
The memory size of the instance variable has been determined whileruntime
Will be calledclass_setIvarLayout
orclass_setWeakIvarLayout
To deal withstrong weak
Reference, so you can’t add instance variables to existing classes. Runtime classes created can be called to add instance variablesclass_addIvar
Function. But it has to be calledobjc_allocateClassPair
After that,objc_registerClassPair
Before, for the same reason
runtime
How to useselector
Find the correspondingIMP
Address (consider instance method and class method respectively)Selector, Method, and IMP
What are the differences and connections between
For instance methods, each instance’s ISA pointer points to the corresponding class object, and each class object has a list of object methods. For class methods, the ISA pointer to each class object points to the corresponding metaclass object, and each metaclass object has a list of class methods. Method list records the name of the Method, Method implementation, and parameter type, in fact, the selector is essentially the name of the Method, through this Method name can be found in the Method list corresponding Method implementation selector, Method and IMP can be described like this: You distribute messages at run time, and each entity in the Method list is a Method and it’s called SEL and it corresponds to a Method implementation IMP
Objc_msgSend, _objc_msgForward
What do they do? What is the message invocation flow in OC
objc_msgSend
It’s used to send messages. inOC
In, all calls to methods are converted to internal message sending execution_objc_msgForward
isIMP
The type (function pointer) is used for message forwarding: when a message is sent to an object and it is not implemented,_objc_msgForward
Will attempt to do message forwarding- During the message invocation,
objc_msgSend
The action is more clear: first inClass
Cache lookup inIMP
If no cache is found, the parent class is initializedClass
Lookup. If the root class is still not implemented, use_objc_msgForward
Function pointer substitutionIMP
. Finally, execute thisIMP
. When you call aNSObject
When an object does not have a method, it does not throw an exception immediately. Instead, it calls the object’s method through multiple layers of forwarding- resolveInstanceMethod:, - forwardingTargetForSelector:, - methodSignatureForSelector:, - forwardInvocation:
Methods. Where the last-forwardInvocation:
There will be oneNSInvocation
Object, this oneNSInvocation
The object holds all information about this method call, includingSelector name, parameter, and return value type
You can start with thisNSInvocation
Gets the values of all the arguments to the call
class
Methods andobjc_getClass
What’s the difference
Object_getClass (obj) returns a pointer to isa in obj. When obj is an instance object, the class in [obj class] is the instance method, which returns the ISA pointer in obj object. The other is that when obj is a class object (including metaclass, root class and root metaclass), the class method is called and the result is itself returned
- OC to one
nil
What happens when the object sends a message
Sending messages to nil in OC is perfectly valid, it just doesn’t do anything at run time; When you send a message to a nil object, the first thing that comes back when you look for the isa pointer to the object is the zero address, so you don’t get any errors, you don’t crash
_objc_msgForward
What does a function do? What happens when you call it directly
_objc_msgForward is a function pointer (of the same type as IMP) for message forwarding; When a message is sent to an object and it is not implemented, _objc_msgForward will try to forward the message. Objc_msgSend is used for message passing. The action of objc_msgSend is clear during message passing: first look for the IMP in the cache of the Class (initialize the cache if there is no cache). If not, look for the parent Class. If _objc_msgForward is called, the IMP will skip the IMP lookup process and directly trigger the message forward. If _objc_msgForward is called, the IMP will skip the IMP lookup process and directly trigger the message forward. Even if the object does implement this method, you can tell objc_msgSend that I didn’t find an implementation of this method in this object, and that it will Crash if used badly
- When will it be reported
unrecognized selector
The abnormal
- When a method is called on an object that has no implementation of the method. Can be achieved by
forward
See the following figure for the process
OC
When sending a message to an object,runtime
Libraries are based on objectsisa
The pointer finds the class that the object actually belongs to, and then looks for the method to run in the list of methods in that class and the list of methods in its parent class. If the corresponding method is still not found in the topmost parent class, the program hangs at runtime and throws an exceptionunrecognized selector sent to XXX
But before that, the OC runtime gives three chances to save the program from crashing- Method Resolution (dynamic message resolution)
OC
Run time call+resolveInstanceMethod:
or+resolveClassMethod:
, gives you the opportunity to provide a function implementation. If you add a function, the runtime restarts the process of sending a message; otherwise, the runtime moves to the next step, message forwarding (Message Forwarding
)
+ (BOOL)resolveInstanceMethod:(SEL) SEL {// If run is implemented, IMP is dynamically resolvedif (sel == NSSelectorFromString(@"run:"// IMP: method implementation => function => function entry => function name //typeVoid void v, id @, SEL: class_addMethod(self, SEL, (IMP)runMethod,"v@:@");
return YES;
}
return[super resolveInstanceMethod:sel]; } // The new run function void runMethod(id self, SEL _cmd, NSNumber *meter) {NSLog(@)"Ran % @", meter);
}
Copy the code
- Fast forwarding if the target object is implemented
-forwardingTargetForSelector:
.Runtime
This method is called, giving you the opportunity to forward the message to other objects. As long as this method returns nonil
andself
The whole process of sending the message will be restarted, and of course the object you sent will become the object you returned. Otherwise, it will continueNormal Fowarding
. This is calledFast
, just to distinguish the forwarding mechanism for the next step. Because this step does not create any new objects, the next step forward will create oneNSInvocation
Object, so it’s relatively faster
/ / message recipient redirect - (id) forwardingTargetForSelector aSelector: (SEL) {if (aSelector == @selector(run:)) {
return[[Person alloc] init]; Return the Person object to receive the message}return [super forwardingTargetForSelector:aSelector];
}
Copy the code
- Normal forwarding this step is
Runtime
One last chance to save the day. First it sends-methodSignatureForSelector:
The message gets the parameter and return value types of the function. if-methodSignatureForSelector:
returnnil
.Runtime
Will be issued-doesNotRecognizeSelector:
Message, and the program hangs. If a function signature is returned,Runtime
I’m going to create oneNSInvocation
Object and send-forwardInvocation:
Message to the target object
/ / get function parameters and return values of type, return the signature - (NSMethodSignature *) methodSignatureForSelector aSelector: (SEL) {if ([NSStringFromSelector(aSelector) isEqualToString:@"run:"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}
return[super methodSignatureForSelector:aSelector]; } // message redirection - (void)forwardInvocation:(NSInvocation *)anInvocation {// get message SEL from anInvocation SEL = anInvocation.selector;if (sel == NSSelectorFromString(@"run:"// Invocation of the current method as IMP // anInvocation. Selector = @selector(readBook:); // [anInvocation invoke]; IMP Person *p = [[Person alloc] init]; // Determine if the Person object method can respond to selif([p respondsToSelector:sel]) {// If the invocation is responsive, the message is forwarded to another object [anInvocation invokeWithTarget:p]; }else{/ / if still can't response, then an error: can't find the response method [self doesNotRecognizeSelector: sel]; }}else{
[super forwardInvocation:anInvocation];
}
}
- (void)doesNotRecognizeSelector:(SEL)aSelector {
[super doesNotRecognizeSelector:aSelector];
}
Copy the code
Since – forwardingTargetForSelector: and – forwardInvocation: all messages can be forwarded to other objects, then where is the difference between the two? The difference is that – forwardingTargetForSelector: only forward the message to an object. The -forwardInvocation: the message can be stored, forwarded when you see fit, or not processed. Modify message target, selector, parameters, etc. Forwarding messages to multiple objects
iOS layoutSubviews
When will it be called
init
Method does not calllayoutSubviews
But withinitWithFrame
Initialization is performed whenrect
The value of theCGRectZero
Is triggeredaddSubview
Will triggerlayoutSubviews
methodssetFrame
Only when setframe
The parameters of thesize
With the originalsize
It is triggered by differenceview
thelayoutSubviews
methods- sliding
UIScrollView
Will be calledscrollview
andscrollview
On theview
thelayoutSubviews
methods- The rotating device will only be called
VC
theview
thelayoutSubviews
methods- Direct call
[self setNeedsLayout];
(This is explained in the Apple documentation above)-layoutSubviews
Method: This method does nothing by default and needs to be overridden by subclasses-setNeedsLayout
Method: mark for need of relayout and call asynchronouslylayoutIfNeeded
Refresh layout, not immediately, butlayoutSubviews
It’s bound to be called-layoutIfNeeded
Method: Call immediately if there is a tag that needs to be refreshedlayoutSubviews
Layout (not called if there is no taglayoutSubviews
If you want to refresh immediately, call first[view setNeedsLayout]
, set the tag to need layout, and call it immediately[view layoutIfNeeded]
Before the view is first displayed, the markup is alwaysNeed to refresh
Can be called directly[view layoutIfNeeded]
- What happens to the following code
@property (nonatomic, strong) NSString *str;
dispatch_queue_t queue = dispatch_queue_create("parallel", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 1000000 ; i++) {
dispatch_async(queue, ^{
self.str = [NSString stringWithFormat:@"changzifuchaung:%d",i];
});
}
Copy the code
Will crash. Because an asynchronous dispatch_async assignment to the STR attribute in the parallel queue DISPATCH_QUEUE_CONCURRENT results in STR already being released and also being released. This is what happens when a message is sent to an object that has freed memory: the STR attribute strong modifier is assigned, as in MRC
- (void)setStr:(NSString *)str{
if (str == _str) return; id pre = _str; [str retain]; //1. Keep the new value _str = STR; //2. Assign [pre release]; //3. Release old value}Copy the code
So if thread A in the concurrent queue executes to step 1 and thread B executes to step 3 before it reaches step 2, then when thread A executes to step 3, the old value will be overfreed, causing A crash by sending messages to the freed object
- Follow-up: How to modify this code to not crash
Atomic atomic: setters are thread-safe, and setters are threadsafe. Setters are threadsafe, and setters are threadsafe. Setters are threadsafe, and setters are threadsafe. 3. Setters that use the weak keyword weak do not retain operations on new values, so they do not cause repeated releases. If you want to use an “weak” lock, you can use an “weak” lock. If you want to use an “weak” lock, you can use an “weak” lock. @synchronized (self) {self. STR = [NSString stringWithFormat:@”changzifuchaung:%d”, I]; Tagged Pointer is a memory technology introduced by Apple on 64-bit systems. For NSString or NSNumber, 64-bit Pointers are 8 bytes long. You can use this space to directly represent values. This will actually convert NSString and NSNumber objects from a pointer to a value type. Setters and getters for value types are atomic, making them thread-safe
- Divergent: The following code does
crash
?
@property (nonatomic, strong) NSString *str;
dispatch_queue_t queue = dispatch_queue_create("parallel", DISPATCH_QUEUE_CONCURRENT);
for(int i = 0; i < 1000000 ; I++) {dispatch_async(queue, ^{self. STR = [NSString stringWithFormat:@"%d",i];
NSLog(@"%d, %s, %p", i, object_getClassName(self.str), self.str);
});
}
Copy the code
Won’t crash. And it turns out that STR is a string of type NSTaggedPointerString. TaggedPointer is an interesting technique that can improve performance and save memory. TaggedPointer is for storing small objects, For example, the Tagged Pointer to NSNumber and NSDate(which can later store small strings) is no longer an address, but a real value. So, it’s not really an object anymore, it’s just a normal variable in an object wrapper that doesn’t have memory stored in the heap, doesn’t need malloc and free, so it’s incredibly fast to read and create
Attached: my blog address