1. Singleton writing
-
(instancetype)sharedInstance { static id sharedInstance = nil;
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init]; });
return sharedInstance; } @property (weak, nonatomic) id analyticsDelegate;
@property (assign, nonatomic) NSInteger statusCode; @synthesize statusCode = _statusCode;
GCD dispatch_time_t timer = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC); dispatch_after(timer, dispatch_get_main_queue(), ^{
});
Copy the code
4. Set the transparency of the parent view, add the child view does not display the solution Set the color of the parent view: _bottomView backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent: 0.5];
5. Calculation time NSDate * date = [NSDate dateWithTimeIntervalSince1970: [finance buildDate longLongValue] / 1000].
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *strDate = [dateFormatter stringFromDate:date];
Copy the code
6. Why copy is used for NSString? Rather than strong?
A->B it is acceptable for A MutableString in A to assign to A Property in B (NSString type). The parent class can accept subclasses. If it’s A retain, it just generates A pointer, increments the counter, And then point to that MutableString. If MString changes, that one in B changes, because it’s the same memory area. Selecting Copy generates another NSString, separate from the MutableString in A.
Same thing with NSArray and NADictionary
The Runtime maintains a Weak table, which stores all the Weak Pointers to an object. The Weak table is a hash table where Key is the address of the specified object and Value is an array of addresses of the specified object. When the object is reclaimed, layers of calls will eventually trigger the following method to set all Weak Pointers to nil.
8, responder chain event transfer and response difference: event transfer is from top to bottom (parent control to child control), event response is from bottom to top (along the responder chain transfer: child control to parent control. So hitTest:withEvent: layer by layer to find the view that responds best, and then touchesBegan:withEvent: Respond to the event, and if it doesn’t respond then go to the superview and then go down and up to the UIApplication and if it doesn’t respond then just disuse the event. A: http://www.jianshu.com/p/c294d1bd963d transfer process keyWindow will call hitTest on its contents view: withEvent: (the method returns is the most suitable processing of the touch events view) to complete the search process. HitTest :withEvent: Internally it first determines whether the view can respond to the touch event. If not, nil is returned, indicating that the view does not respond to the touch event. Then call pointInside:withEvent: (this method is used to determine whether the click event occurred in the current view range). If pointInside:withEvent: returns NO, then hiteTest:withEvent: also returns nil directly. If pointInside:withEvent: returns YES, a hitTest:withEvent: message is sent to all the children of the current view, traversed from the topmost view all the way to the bottom view, from the end of the Subviews array. Until any subview returns a non-empty object or all subviews are iterated; The first time a subview returns a non-empty object, the hitTest:withEvent: method returns the object. If all subviews return no, the hitTest:withEvent: method returns the view itself. HitTest: The underlying implementation // Point is a point in the view’s coordinate system
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // 1. Judge oneself can receive touch events if (self userInteractionEnabled = = NO | | the self. The hidden = = YES | | the self. The alpha < = 0.01) return nil; // 2. Determine if the touch point is within its range. [self pointInside:point withEvent:event]) return nil; Int count = self.subviews.count; for (int i = count – 1; i >= 0; i–) { UIView *childView = self.subviews[i]; CGPoint childPoint = [self convertPoint:point toView:childView]; UIView *fitView = [childView hitTest:childPoint withEvent:event]; if (fitView) { return fitView; }} // View return self; } http://www.jianshu.com/p/2f664e71c527 http://www.cocoachina.com/ios/20160630/16868.html
9. Expand button click range with responder chain rewrite pointInside: withEvent: #import <UIKit/ uikit. h> @interface UIButton (test) @property(nonatomic, assign) UIEdgeInsets hitTestEdgeInsets; @end
#import “UIButton+test.h” #import <objc/runtime.h>
@implementation UIButton (test) @dynamic hitTestEdgeInsets;
static const NSString *KEY_HIT_TEST_EDGE_INSETS = @”HitTestEdgeInsets”;
-(void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets { NSValue *value = [NSValue value:&hitTestEdgeInsets withObjCType:@encode(UIEdgeInsets)]; objc_setAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
-(UIEdgeInsets)hitTestEdgeInsets { NSValue *value = objc_getAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS); if(value) { UIEdgeInsets edgeInsets; [value getValue:&edgeInsets]; return edgeInsets; }else { return UIEdgeInsetsZero; }}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || ! self.enabled || self.hidden) { return [super pointInside:point withEvent:event]; } CGRect relativeFrame = self.bounds; CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets); Return CGRectContainsPoint(hitFrame, point); } @end
10, interview questions at http://www.cocoachina.com/programmer/20151019/13746.html
11, the observer pattern () http://www.jb51.net/article/76122.htm http://www.cnblogs.com/goodboy-heyang/p/5265675.html kvo: The essence of KVO is that when an observer registers an object’s property and the ISA pointer of the observed object is modified, the ISA pointer points to an intermediate class, not the real class. So the ISA pointer does not need to point to the actual class of the instance object. So it’s best for our program not to rely on isa Pointers. When calling a class method, it is best to specify the class name of the object instance. When you observe an object, you dynamically create a subclass of the object class. This subclass overrides the setter method for the property being observed and points the isa pointer to the newly created subclass. In Objective-C an object looks up a list of methods in the corresponding class using an ISA pointer, so you can think of this object as an instance object of a new subclass. Overridden setter methods notify observers of changes in object property values after calling the original setter methods. addObserver:forKeyPath:options:context: observeValueForKeyPath:ofObject:change:context
When an object of a class is observed for the first time, the system dynamically creates a derived class of that class at run time, in which setter methods for any observed properties in the base class are overridden. Derived classes implement the true notification mechanism in the setter methods that are overridden, just as we implemented the manual key-value observation earlier. This is done on the basis that setting the property calls setter methods, and overrides get the notification mechanism that KVO needs. Of course, the premise is to change the attribute value by following the KVO attribute setting method. If you only modify the corresponding member variable of the attribute directly, KVO cannot be realized. The derived class also overrides the class method to “fool” external callers that it is the original class. The system then points the isa pointer to this object to the newly born derived class, so the object becomes an object of that derived class, and calls to setters on that object invoke the override setter, thereby activating the key-value notification mechanism. In addition, the derived class overrides the dealloc method to release resources. Kvo @implementation NSObject (WSG)
-
(void)wsg_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{
// change the isa pointer to the current object; // change the isa pointer to the current object NSString *oldClass = NSStringFromClass([self class]); / / new class nsstrings * newClass = [@ “wsgKVO_” stringByAppendingString: oldClass]; // Create a subclass object Class myClass = objc_allocateClassPair([self Class], [newClass UTF8String], 0); // Register class objc_registerClassPair(myClass);
// add the setName method to the class class_addMethod(myClass, @selector(setName:), (IMP)setName, “v@:@”);
Object_setClass (self, myClass);
// Save the observer object objc_setAssociatedObject(self, @”objc”, observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // save keypath objc_setAssociatedObject(self, @”wsgkeypath”, keypath, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
// Call setName(id self,SEL _cmd,NSString *newName){// Call setName(id self,SEL _cmd,NSString *newName) //objc_msgSendSuper()
// Change self's isa pointer to the parent class by calling setName and notifies the observer that the value has changed and then changing back to self's ISA pointer to subclass id class = [self class]; Object_setClass (self, class_getSuperclass(class)); // Alter self's isa to point to the parent object_setClass(self, class_getSuperclass(class)); /* id self, SEL op,... */ to compile by going to build-setting search objc_msg and setting enable to NO objc_msgSend(self,@selector(setName:),newName); Id objc = objc_getAssociatedObject(self, @"objc"); id keypath = objc_getAssociatedObject(self, @"wsgkeypath"); objc_msgSend(objc, @selector(observeValueForKeyPath:ofObject:change:context:),self,keypath,nil,nil); Object_setClass (self, class);Copy the code
} @end
Internal implementation of KVC(key-value-coding) : it is key-value Coding. When an object calls setValue, (1) it first finds the environment parameters required for running the method according to the method name. (2) He will find a specific method to implement the interface from his OWN ISA pointer combined with the environment parameters. (3) And then directly find the specific method to achieve.
Delegate: Usually the relationship between sender and receiver is a direct one to one relationship. The purpose of an agent is to change or transfer the chain of control. Allows a class to notify other classes at certain times without having to retrieve Pointers to those classes. You can reduce framework complexity. The sender of the message tells the receiver that an event is about to occur, the delegate agrees, and the sender responds to the event. The delegate mechanism allows the receiver to change the behavior of the sender.
Notification: Observer pattern. Usually the relationship between sender and receiver is indirect many-to-many. The sender of a message notifies the receiver that an event has occurred or will be sent, and that is all. The receiver cannot in turn influence the sender’s behavior.
1). The efficiency of delegate must be higher than that of NSNotification.
2). The delegate method is more direct than notification. The most typical feature of the delegate method is that it often needs to pay attention to the return value, which is the result of the delegate method. For example, -windowshouldClose:, you care whether you return yes or no. So delegate methods tend to include the catchy word should. It’s like you’re my delegate, and I’m going to ask you if I want to close the window do you want to close it? You need to give me an answer, and I will decide what to do next based on your answer. On the contrary, the best feature of Notification is that I don’t care about the attitude of the recipient. I just put the notification out. It’s up to you whether you accept it or not, and I don’t care about the result. So notification often did this words, such as NSWindowDidResizeNotification, what nswindow object released after the notification is whether the reaction will not wait for the recipient.
1) If the two modules are not closely connected, they use notification to transmit values, for example, notificaiton is used to transmit values between multiple threads.
2) Delegate is a simple callback, which is mainly used in a module. For example, when a function at the bottom level is completed and some values need to be transmitted to the upper level, the upper level function should be transmitted to the lower level through the delegate, and then the delegate should be called at the bottom level. They are all in the same module and complete a function. For example, NavgationController returns A button from interface B to point A (calling popViewController method) using delegate.
Delegate why weak @protocol LYSunDelegate @end
@interface LYSun : NSObject @property (nonatomic, weak) iddelegate; @end
#import “LYPerson.h” #import “LYSun.h”
@interface LYPerson() /** strong reference dog*/ @property (nonatomic, strong) LYSun *sun; @end
@implementation LYPerson
- (instancetype)init { self = [super init]; If (self) {// instantiate dog self.sun = [[LYSun alloc] init]; // Sun’s delegate refers to self,self’s retainCount depends on the delegate modifier, weak: retainCount does not change, strong: retainCount + 1 self.sun.delegate = self; } return self; }
- (void)dealloc {NSLog(@”LYPerson—- destroy “); } @end
LYPerson *person = [[LYPerson alloc] init]; LYPerson *person = [[LYPerson alloc] init]; When the delegate uses strong: When the viewController wants to release the person after it doesn’t reference the person, it finds that sun.delegate is still strongly referencing the person, and the person’s retainCount is 1, so the person won’t be released, and sun won’t release the person either. This is what causes memory leaks caused by circular references when the delegate is weak: When the viewController does not reference the person, the person’s retainCount is 0, which of course can be freed, and the person is freed, and the Sun is freed
-(void)setAge (NSInteger)age {_age =age; (void)setAge (NSInteger) {_age =age; } -(NSInteger )age { return _age; } //retain attributes -(void)setArray:(NSArray *)array {if (_array! =array) { [_array release]; _array =[array retain]; }}
-(NSArray*)array{ return [[_array retain]autorelease]; -(void)setName:(NSString *)name {if (_name! =name) { [_name release]; _name = [name copy]; } } -(NSString *)name { return [[_name retain]autorelease]; } 14: SEL http://www.imlifengfeng.com/blog/?p=398 also called a selector, a pointer to the selector is one way to say essentially, SEL is a pointer to the method (accurately, is only a according to the method name hash of the KEY value, Can only represent a method), its existence is only to speed up the method of query speed IMP is the implementation of SEL and IMP is one to one correspondence
15: tableview computational cell height 1: special layout to compute the position of each control: such as YYKit in https://github.com/ibireme/YYKit; Refresh the main thread after calculating in the child thread to improve refresh efficiency. 2. Autolayout automatically ADAPTS to height; 3. The whole code calculates the height in the layoutSubviews of the cell. http://www.imlifengfeng.com/blog/?p=501 tableview optimization:
Coretext Draws text
CTFramesetter is initialized by CFAttributedString(NSAttributedString), which can be thought of as a Factory for CTFrame, passing in CGPath to generate the corresponding CTFrame and render it: Use CTFrameDraw to draw directly with CTFrame as parameter or use CTLine from CTFrame to draw with CTLineDraw after fine tuning.
A CTFrame is made up of a line of CLine, and each CTLine contains several TruNs (the smallest unit of character drawing). The corresponding methods can be used to obtain the truNs and CTlines in different positions to respond to touch events in different positions.
http://blog.devtang.com/2015/06/27/using-coretext-1/ http://blog.devtang.com/2015/06/27/using-coretext-2/ http://blog.csdn.net/hopedark/article/details/50174157
Runloop Runloop can only be executed in one mode and then sleep for the next. NSRunLoopCommonModes: placeholder modes UITrackingRunLoopMode:UI modes NSDefaultRunLoopMode: default modes Each mode corresponds to source, Timer, and Observer Source: source0: non-system kernel source1: system kernel
Concurrent Dispatch Queue (Concurrent Dispatch Queue) Serial Dispatch Queue (dispatch_async) allows multiple tasks to be executed in parallel (automatically enabling multiple threads to execute tasks at the same time) Allow tasks to be executed one after another (after one task is executed, the next task is executed) Tasks: Sync: Can only execute tasks in the current thread without the ability to start new threads Async: Can execute tasks in a new thread with the ability to start new threads
// dispatch_queue_t queue = dispatch_queue_create(“com.sunny.test”, DISPATCH_QUEUE_CONCURRENT); // dispatch_queue_t queue = dispatch_queue_create(“com.test”, DISPATCH_QUEUE_SERIAL); Dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); // Global queue priority DISPATCH_QUEUE_PRIORITY_HIGH DISPATCH_QUEUE_PRIORITY_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW DISPATCH_QUEUE_PRIORITY_BACKGROUND
Dispatch_sync (queue, ^{NSLog(@”%@”,[NSThread currentThread]); }); Dispatch_async (queue, ^{NSLog(@”%@”,[NSThread currentThread]); });
Dispatch_async (dispatch_get_main_queue(), ^{NSLog(@”2——-%@”,[NSThread currentThread]); });
// Dispatch_after (dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), dispatch_get_main_queue(), ^{// Execute the code here asynchronously after 2 seconds… NSLog(@”run—–“); });
// Perform static dispatch_once_t onceToken once. Dispatch_once (&onceToken, ^{// only execute code once(thread-safe by default)});
Dispatch_barrier_async requires two sets of operations to be performed asynchronously, and when the first set of operations is complete, Dispatch_queue_t queue = dispatch_queue_create(“12312312”, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"----1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----2-----%@", [NSThread currentThread]);
});
Copy the code
Dispatch_barrier_async (queue, ^{NSLog(@”—-barrier—–%@”, [NSThread currentThread]); });
dispatch_async(queue, ^{
NSLog(@"----3-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----4-----%@", [NSThread currentThread]);
});
Copy the code
Queue group dispatch_group_t group = dispatch_group_create();
Dispatch_group_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// Perform one asynchronous operation});
Dispatch_group_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// Perform one asynchronous operation});
^{dispatch_group_notify(dispatch_get_main_queue(), dispatch_get_main_queue(), ^{ });
// dispatch_semaphore_create dispatch_semaphore_signal // wait for semaphore_signal dispatch_semaphore_wait
// create a parallel queue dispatch_queue_t queque = dispatch_queue_create(“GoyakodCreated”, DISPATCH_QUEUE_CONCURRENT); // Dispatch_async (queque, ^{dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); [self getToken:semaphore]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); [self request]; }); The getToken method includes dispatch_semaphore_signal(semaphore); Self. timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0)); dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1000000000, 0); dispatch_source_set_event_handler(self.timer, ^{ NSLog(@”———%@”,[NSThread currentThread]); }); dispatch_resume(self.timer);
NSString *testStr1 = @”a”; NSString *testStr2 = [NSString stringWithString:@”b”]; NSString *testStr3 = [NSString stringWithFormat:@”c”]; TestStr4 = [[NSString alloc] initWithString:@”d”]; NSString *testStr5 = [[NSString alloc] initWithFormat:@”e”]; Test1,test2, and test4 are all in a constant memory region. Test1,test2,test4, test1,test2,test4, test3,test5, test1,test2,test4, test3,test5, test1,test2,test4 For test3 and test5, texst3 is recommended
20, dsYM file analysis xcode packaging will be generated after archive file. Xcarchive path (~ / Library/Developer/xcode/Archives) every xx. The app and Xx.app. dSYM has corresponding UUID, and crash file also has its own UUID. As long as the UUID of the three files is consistent, the error function address can be resolved through the command line. DSYM dwarfdump — UUID xx.app.dSYM check the function atos-arch arm64-O Zeus -L 0x10063000 that corresponds to the crash address 0x00000001009795d4
HMAC encryption replaces MD5 encryption MD5 encryption with salt encryption is dangerous in APP. If salt leaks, the entire encryption process will be threatened. Modification of salt affects all users. // HMACMD5 encryption method Each user has a key that can be updated from the server
- (NSString *)hmacMD5StringWithKey:(NSString *)key { const char *keyData = key.UTF8String; const char *strData = self.UTF8String; uint8_t buffer[CC_MD5_DIGEST_LENGTH]; CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer); return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH]; } After HMAC encryption, the password +201711302229 MD5 is encrypted to the server. The verification server also adds the HMAC password to the time (to minutes) to match the password sent by the APP.
@interface Person: NSObject{@public NSString *_name; } @property (nonatomic,copy) NSString *age; @end Person *p = [[Person alloc] init]; p->_name = @”sunny”; P.age = @”18″; // The value of an instance variable can be observed by using the set method
Call functions allocate stack space. No return allocates stack space all the time.
24, 2, run on iOS 11 64 px tableView downward migration or 20 px, 11 abandoned automaticallyAdjustsScrollViewInsets because iOS, But to add to the UIScrollView contentInsetAdjustmentBehavior properties. The way to avoid this pit is to say if (@available(iOS 11.0, *)) { _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; }else { self.automaticallyAdjustsScrollViewInsets = NO; }
25, set the navigation bar to the self. The navigationController. NavigationBar. Translucent = YES; self.navigationController.navigationBar.barTintColor = clear_color; [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault]; [self.navigationController.navigationBar setShadowImage:[UIImage new]];
26, set the navigation bar to the self. The opaque navigationController. NavigationBar. Translucent = NO; self.navigationController.navigationBar.barTintColor = RGBCOLOR(64, 98, 153); [self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault]; [self.navigationController.navigationBar setShadowImage:nil];
27, CFBundleURLType: current APP record of scheme through a schema can open the APP in other APP LSApplicationQueriesSchemes from iOS9 were introduced. This APP is not allowed to query for scheme when the other APP is invoked. This APP is not allowed to query for scheme when the other APP is invoked. Both the caller and the called need to set up a whitelist, one party wants to call, the other party needs to also know that you will call, more secure