IOS (8)

ALAssetsLibrary assetForURL: Always Returning nil for photos in “My Photo Stream” in iOS 8.1

  • (void)loadItem:(NSURL *)url withSuccessBlock:(void (^)(void))successBlock andFailureBlock:(void (^)(void))failureBlock {

[library assetForURL:url resultBlock:^(ALAsset *asset) { if (asset){ ////////////////////////////////////////////////////// // SUCCESS POINT #1 – asset is what we are looking for / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / successBlock ();} else {/ / On iOS 8.1 [library assetForUrl] Photo Streams always returns nil. Try to obtain it in an alternative way

            [library enumerateGroupsWithTypes:ALAssetsGroupPhotoStream
                                   usingBlock:^(ALAssetsGroup *group, BOOL *stop)
             {
                 [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
                     if([result.defaultRepresentation.url isEqual:url])
                     {
                         ///////////////////////////////////////////////////////
                         // SUCCESS POINT #2 - result is what we are looking for
                         ///////////////////////////////////////////////////////
                         successBlock();
                         *stop = YES;
                     }
                 }];
             }

                                 failureBlock:^(NSError *error)
             {
                 NSLog(@"Error: Cannot load asset from photo stream - %@", [error localizedDescription]);
                 failureBlock();

             }];
        }

    }
    failureBlock:^(NSError *error)
    {
        NSLog(@"Error: Cannot load asset - %@", [error localizedDescription]);
        failureBlock();
    }
Copy the code

]; }

Ref:stackoverflow.com/questions/2…


About a memory problem

The following tests do the same for the NSNumber type.

@interface AJKTestViewController () @property(nonatomic,strong) NSString* str1; @property(nonatomic,weak) NSString* str2; @end @implementation AJKTestViewController - (void)viewDidLoad { [super viewDidLoad]; self.str1=[[NSMutableString alloc] initWithString:@"huhu"]; self.str2=self.str1; self.str1=nil; NSLog(@"str1:%@ str2:%@",self.str1,self.str2); Str1 :null str2:null self.str1=@"huhu"; self.str2=self.str1; self.str1=nil; NSLog(@"str1:%@ str2:%@",self.str1,self.str2); Str1 :(null) str2:huhu return; }Copy the code

NSSecureCoding protocol is used for encoding and decoding

While you can’t store executable code in an NSCoding file (at least not on iOS), a hacker could trick your app into instantiating a class object that you’d never imagine, or instantiating a class object in an environment that you’d never imagine. While it’s hard to do any real harm, it can certainly lead to app crashes or user data loss.

In iOS6, apple introduced a new protocol based on NSCoding called ns secure recoding. NSSecureCoding is almost identical to NSCoding, except that when decoding you specify the key and class of the object to decode, and if the specified class does not match the class of the object decoded from the file, NSCoder will throw an exception to tell you that the data has been tampered with

@interface Foo : NSObject @property (nonatomic, strong) NSNumber *property1; @end@implementation Foo // We have to return YES + (BOOL)supportsSecureCoding {return YES; } - (id)initWithCoder:(NSCoder *)coder { if ((self = [super init])) { //security encoding Decode the property values by key, specifying the expected class _property1 = [coder decodeObjectOfClass:[NSNumber class] forKey:@"property1"]; // Non-security coding // _property1 = [coder decodeObjectForKey:@"property1"]; } return self; } - (void)encodeWithCoder:(NSCoder *)coder { // Encode our ivars using string keys as normal [coder encodeObject:_property1 forKey:@"property1"]; } @endCopy the code

About the Chunked encoding

When chunked encoding is used, the Content-Length header is ignored and ends with an empty chunk

Data is sent in a series of chunks. The Content-Length header is omitted in this case and at the beginning of each chunk you need to add the length of the current chunk in hexadecimal format, followed by ‘\r\n’ and then the chunk itself, followed by another ‘\r\n’. The terminating chunk is a regular chunk, with the exception that its length is zero. It is followed by the trailer, which consists of a (possibly empty) sequence of entity header fields.

Chunked encoding is useful when larger amounts of data are sent to the client and the total size of the response may not be known until the request has been fully processed. For example, when generating a large HTML table resulting from a database query or when transmitting large images. A chunked response looks like this:

HTTP/1.1 200 OK 
Content-Type: text/plain 
Transfer-Encoding: chunked
7\r\n
Mozilla\r\n 
9\r\n
Developer\r\n
7\r\n
Network\r\n
0\r\n 
\r\n
Copy the code

Chunk usage scenarios:

The content can be broken up into a number of chunks when creating a large HTML table. each of which is prefixed by its size in bytes. A zero size chunk indicates the end of the response message. If a server is using chunked encoding it must set the Transfer-Encoding header to “chunked”.

Chunked encoding is useful when a large amount of data is being returned to the client and the total size of the response may not be known until the request has been fully processed. An example of this is generating an HTML table of results from a database query. If you wanted to use the Content-Length header you would have to buffer the whole result set before calculating the total content size. However, with chunked encoding you could just write the data one row at a time and write a zero sized chunk when the end of the query was reached.

refLhttps://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding

About transfer-encoding in HTTP

This feature is used to describe both ends, regardless of the specific resource. The transfer-encoding header specifies The form of Encoding used to safely Transfer The entity to the user. Transfer-Encoding is a hop-by-hop header, that is applying to a message between two nodes, not to a resource itself. Each segment of a multi-node connection can use different Transfer-Encoding values. If you want to compress data over the whole connection, use the end-to-end header Content-Encoding header instead.

Transfer-Encoding: chunked
Transfer-Encoding: compress
Transfer-Encoding: deflate
Transfer-Encoding: gzip
Transfer-Encoding: identity
// Several values can be listed, separated by a comma
Transfer-Encoding: gzip, chunked
Copy the code

About if-range in HTTP

If-range is often used to restore the download, to ensure that some of the downloaded files have not changed, so that the download can continue

The If-Range request HTTP header makes the range request conditional: if the condition is fulfilled, the range request will be and the server send back a 206 Partial Contentanswer with the appropriate body. If the condition is not fulfilled, the full resource is sent back, with a 200 OK status. This header can be used either with a Last-Modified validator, or with an ETag, but not with both.

The most common use case is to resume a download, to guarantee that the stored resource has not been modified since the last fragment has been received.

Syntax

If-Range: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
If-Range: <etag>
Copy the code

Ref:developer.mozilla.org/en-US/docs/…

Expire headers, Last Modified headers or ETags in the HTTP cache

Expires and cache-Control are “strong Caching headers”

Last-Modified and ETag are “weak caching headers”

First the browser check Expires/Cache-Control to determine whether or not to make a request to the server

If have to make a request, it will send Last-Modified/ETag in the HTTP request. If the Etag value of the document matches that, the server will send a 304 code instead of 200, and no content. The browser will load the contents from its cache.

I recommend using one of the strong caching headers, along with one of the weak caching headers.

So Expires and Cache-control determines whether the browser makes a second request. The Last Modified Header or ETags determines if 304 is returned for the second request, and if 304 is returned, the cached data is used directlyCopy the code

ref:

HTTP caching browser Cache last-modified/Etag/Expires/cache-control explanation ChenYilong/ParseSourceCodeStudyCopy the code

** About HTTP caching in IOS **

Only GET 1. The HTTP protocol, a cache control 2. Note: * if we use the IOS caching mechanism, the caching policy for NSURLRequestReloadIgnoringCacheData. It's approach is to cache the query parameter of value as the key, the corresponding results as the value. * NSURLRequestUseProtocolCachePolicy. The default cache policy for a Request. Is more complex, it is generally use caching strategy in the HTTP protocol. * if using the last-modified and ETag, so caching strategies must use NSURLRequestReloadIgnoringCacheData strategy, ignore the cache, Check with the server each time. Cache:Copy the code

ETag: "50b1C1d4f775C61 :df3" client query update format is like: if-none-match: W/" 50B1C1D4F775C61: DF3 "If the ETag value of the server is the same as that of the client, the HTTP status code is 304 and data is not returned.Copy the code

Ref: talk about HTTP caching strategies in iOS – Chesterlee ‘s Zen ChenYilong/ParseSourceCodeStudy

About OSAtomicCompareAndSwap32Barrier

OSAtomicCompareAndSwap32Barrier(old, new, addr)

This function is then translated into pseudocode to look like this:

if (*addr == oldvalue) {
    *addr = newvalue;
    return 1;
} else {
    return 0;
} 
Copy the code

The difference between Xib and Storyboard

SB:

In team development, it is easier to change a file at the same time. A small change to SB files will cause the entire SB file to be recompiled. Components in SB are not reusable. For example, automatic cell. advantage: 1. 2. Automatic cell and segue are easy to use.Copy the code

Xib:

Reading a XIB involves a disk operation and a xiB file parsing operation. Try not to use xib in dynamic table. Static table can use XIB. 3. After xiB is loaded, all views above will be loaded into memory. Sometimes it's better to load the view dynamically.Copy the code

Ref:stackoverflow.com/questions/2… Stackoverflow.com/questions/1…

About MVC and MVVM

1. For MVC, in iOS development, the system has implemented a public view class: UIView and a controller class: UIViewController. Most of the time, we need to inherit these classes to implement our program logic, so we can hardly escape the MVC design pattern. MVC’s layered approach is clear, but if used incorrectly, it can lead to a lot of code being concentrated in the Controller, turning the MVC pattern into a Massive View Controller pattern.

2.Controller is the least reusable, because we generally do not put complicated business logic in the Model, so it can only be put in the Controller. The Controller is difficult to test because it is so tightly coupled to the View that you need to mock the View and View lifecycle frequently to test it; And when you write your controller code in this way, the business logic code will be cluttered by the view layout code

3. Although you can delegate some of the business logic and data transformation work in the controller to the Model. Because the main responsibility of View is to show the user’s operation behavior to the Controller.

How do I slim down my ViewController?

IO is a popular iOS development blog. Its first tutorial, Lighter View Controllers, describes many of these techniques. Let’s summarize the point:

Separate the UITableView's Data Source into another class. Separate the logic for data retrieval and transformation into a separate class. Separate the logic of the assembled control into another classCopy the code

1. Strip network requests away

2. New handwritten code, like to put one UILabel, UIButton, UITextField in Controller on self.view with addSubView method. I suggest that you take this code out of the Controller in two ways.

Method one: Construct a special UIView subclass that is responsible for assembling these controls. This is the most thorough and elegant way to do this, but it is a little more troublesome because you need to take over the control’s event callbacks and then expose them all back to the Controller.

Method 2: Use a static Util class to help you assemble UIView. This approach is slightly less radical, but simpler.

The emergence of MVVM is mainly to solve the problem that controllers become increasingly large and difficult to maintain in the development process. Therefore, MVVM frees the task of data processing from Controller and makes Controller only need to focus on data allocation. The ViewModel takes care of the data processing and notifies the View to respond to changes to the ViewModel.

MVVM is built based on the architectural idea of fat Model, and then split into two parts of fat Model: Model and ViewModel. The ViewModel is essentially a Model layer (because it’s part of the fat Model), so it’s not a good idea for a View to hold the ViewModel directly, because the ViewModel may not only serve a particular View, Using a looser binding reduces the coupling between the ViewModel and View.

The Model layer is necessary. We need something to act as a DTO(data transfer object). Of course, dictionaries are also possible. Model layer is a relatively thin layer, if you have learned Java partners, JavaBean should not be unfamiliar with it.

The ViewModel layer, which is the glue between the View and Model layers, is a great place to put user input validation logic, View display logic, network requests, and all sorts of other code. In plain English, the business logic and page logic of the ViewController layer are removed and placed in the ViewModel layer.

The View layer, the ViewController layer, its job is to get the data from the ViewModel layer and display it.

There are two main criticisms of MVVM:

First point: Data binding makes bugs hard to debug. If you see an exception in the interface, you may have a Bug in your View code or a problem in your Model code. Data binding allows bugs in one location to be quickly transferred to another location, making it difficult to locate the original problem.

Second point: For large projects, data binding requires more memory.

About ReactiveCocoa

ReactiveCocoa

Functional Programming and React Programming are also popular concepts. The combination of them makes it easy to bind data. Thus, in iOS programming, ReactiveCocoa came out of nowhere, and its concepts are very new, including:

In Functional Programming, functions become first-class citizens, having the same functions as objects, such as passing as parameters, returning as values, and so on. This is Cool when you look at the many functional programming features that the Swift language brings. React Programming, we used to have weak event-based processing, now we have input-based processing (called Signal in ReactiveCocoa). The input can also be used for various combinations or filters through functional programming, showing a variety of flexible processing. Stateless is the devil of a function. Stateless makes the function more testable. Immutable data is unchangeable, making software logical and easily testable.

Notes about the use of appearance

Appearance attribute reset, below, to pass setMessageTextColor method to change the text color, and can not directly use _bubbleView. TextLabel. TextColor = to set the text color, it doesn’t effect to do so

EaseMessageCell *cell = [self appearance]; cell.messageTextColor = [UIColor blackColor]; - (void)setMessageTextColor:(UIColor *)messageTextColor { _messageTextColor = messageTextColor; if (_bubbleView.textLabel) { _bubbleView.textLabel.textColor = _messageTextColor; }}Copy the code

about

NSLayoutRelationGreaterThanOrEqual and NSLayoutRelationLessThanOrEqual is a range of constraints, so on the basis of the scope of this constraint, you can also add other constraint, further restrictions. The end result, then, is that as long as these constraints don’t conflict, you get scopes.

- (void)viewDidLoad { [super viewDidLoad]; _containerView.layer.masksToBounds = YES; _containerView. Layer. BorderWidth = 1.0 f; _containerView.layer.borderColor = [UIColor redColor].CGColor; self.tipLabel.text = @"tutuge.me\niOS"; [_containerView addSubview:self.tipLabel]; [_tipLabel sizeToFit]; [_tipLabel mas_makeConstraints:^(MASConstraintMaker *make) { 1000 make priority. Left. GreaterThanOrEqualTo (_containerView. Mas_left); make. Right. LessThanOrEqualTo (_containerView. Mas_right);  make.top.greaterThanOrEqualTo(_containerView.mas_top); make.bottom.lessThanOrEqualTo(_containerView.mas_bottom); _leftConstraint = make.centerx.equalto (_containerView.mas_left).with.offset(50).priorityHigh(); // The priority is lower than the boundary condition _topConstraint = make.centery.equalto (_containerView.mas_top).with.offset(50).priorityHigh(); // The priority is lower than the boundary condition make.width.mas_equalTo(CGRectGetWidth(_tipLabel.frame) + 8); // make.height.mas_equalTo(CGRectGetHeight(_tipLabel.frame) + 4);}]; / / this constraint ensures UILabel the size of the size of its content. [_tipLabel setContentHuggingPriority: UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; [_tipLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panWithGesture:)]; [_containerView addGestureRecognizer:pan]; } #pragma mark - Pan gesture - (void)panWithGesture:(UIPanGestureRecognizer *)pan { CGPoint touchPoint = [pan locationInView:_containerView]; _logLabel.text = NSStringFromCGPoint(touchPoint); _leftConstraint.offset = touchPoint.x; _topConstraint.offset = touchPoint.y; }Copy the code

In the following constraints, we want viewToAdd to be as large as possible:

[self.scrollViewContainer addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|-(>=32)-[viewToAdd(<=576)]-(>=32)-|" 
                         options:0 
                         metrics:nil  
                           views:NSDictionaryOfVariableBindings(viewToAdd)
]];
Copy the code

The above constraint does not meet this requirement. The correct constraint is:

"H:|-(>=32,==32@900)-[viewToAdd(<=576)]-(>=32,==32@900)-|"
Copy the code

Weak references should be used to refer to UI components

In general, you should use weak to declare the control, whether referring to Xib or writing UI code directly. In pure code, if you use strong to declare the control, there are two situations: If the control is removed, the line referenced by the subviews in the view of the Controller will be cut, but the line referenced by the strong property (pointer) will still exist. Since ARC uses strong references, the control will not be destroyed by ARC, so it will always use memory. Until the controller is destroyed. In other words, UIView components should be operated by the corresponding UIView Api, and its memory will be managed by UIView and its parent View..

Solution: Declare the attribute as weak and use a temporary variable (strong by default) to point to the weak attribute

Copy and MutableCopy

The code is as follows:

@implementation - (id)copyWithZone:(nullable NSZone *)zone{MyObject* o=[[MyObject alloc] init]; o.ivar=self.ivar; return o; } - (id)mutableCopyWithZone:(nullable NSZone *)zone{ MyObject* o=[[MyObject alloc] init]; o.ivar=self.ivar; return o; } @end // array operation NSMutableArray* arr=[[NSMutableArray alloc] init]; for(int i=0; i<2; i++){ [arr addObject:[[MyObject alloc] init]]; } NSLog(@"arr:%@",arr); NSMutableArray* arr2=[arr mutableCopy]; NSLog(@"arr2:%@",arr2); NSMutableArray* arr4=[arr copy]; NSLog(@"arr4:%@",arr4); NSMutableArray* arr3=[[NSMutableArray alloc] initWithArray:arr]; // NSMutableArray* arr3=[[NSMutableArray alloc] initWithArray:arr copyItems:YES]; NSLog(@"arr3:%@",arr3); MyObject* m=arr3.firstObject; m.ivar=19; NSLog(@"arr3:%@",arr3); Output: 2016-10-28 11:21:30.060 TESTConstraintWidth[86332:902586] arr:("<MyObject: 0x6080000132f0>", "<MyObject: 0x608000013310>") 2016-10-28 11:21:30.060 TESTConstraintWidth[86332:902586] arr2:("<MyObject: 0x6080000132f0>", "<MyObject: 0x608000013310>") 2016-10-28 11:21:30.060 TESTConstraintWidth[86332:902586] arr4:("<MyObject: 0x6080000132f0>", "<MyObject: 0x608000013310>") 2016-10-28 11:21:30.060 TESTConstraintWidth[86332:902586] arr3:("<MyObject: 0x6080000132f0>", "<MyObject: 0x608000013310>") 2016-10-28 11:21:40.991 TESTConstraintWidth[86332:902586] arr3:("<MyObject: 0x6080000132f0>", "<MyObject: 0x608000013310>" )Copy the code

1. The first thing to make clear is that MutableCopy is used for arrays. The properties of the array that MutableCopy produces are independent. And in the array

The objects are the same, so the semantics of MutableCopy are intact.

If you want to copy an array of objects while generating a new array, use the following method:

NSMutableArray* arr3=[[NSMutableArray alloc] initWithArray:arr copyItems:YES]; NSMutableArray* arr3=[NSMutableArray alloc] initWithArray:arr copyItems:YES];Copy the code

2. For copy and mutableCopy of container classes, distinguish the container from the objects in the container.

Constraints on the parent view

When a child view has intrinsicContentSize, the parent view can only set constraints on its location, not its size, which is automatically calculated to fit its child’s content.

- (void)viewDidLoad { [super viewDidLoad]; UIView* v=[[UIView alloc] init]; v.backgroundColor=[UIColor redColor]; v.translatesAutoresizingMaskIntoConstraints=NO; [self.view addSubview:v]; / / this view I only set the position constraints [self. View addConstraint: [NSLayoutConstraint constraintWithItem: v attribute: NSLayoutAttributeLeft RelatedBy: NSLayoutRelationEqual toItem: self. The view attribute: NSLayoutAttributeLeft multiplier: 1.0 f constant: 20]]. [self.view addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeTop RelatedBy: NSLayoutRelationEqual toItem: self. The view attribute: NSLayoutAttributeTop multiplier: 1.0 f constant: 100]]. // Add a UILabel to the view above, then the view above will adapt to the size of the UILabel. UILabel* textLabel = [[UILabel alloc] init]; textLabel.translatesAutoresizingMaskIntoConstraints = NO; textLabel.backgroundColor = [UIColor clearColor]; textLabel.numberOfLines = 0; textLabel.textAlignment=NSTextAlignmentCenter; textLabel.text=@"kjdflkajsdfljsaf"; [v addSubview:textLabel]; NSDictionary* viewDic=@{@"v":textLabel}; [v addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(==5)-[v]-(==5)-|" options:0 metrics:nil views:viewDic]]; [v addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(==5)-[v]-(==5)-|" options:0 metrics:nil views:viewDic]]; }Copy the code

See the example project: TESTConstraintWidth

= = = = = = = = = = = = = = = = = = = = the other case = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

- (void)viewDidLoad { [super viewDidLoad]; UIView* v=[[UIView alloc] init]; v.backgroundColor=[UIColor redColor]; v.translatesAutoresizingMaskIntoConstraints=NO; [self.view addSubview:v]; [self.view addConstraint:[NSLayoutConstraint constraintWithItem:v] [self.view addConstraint constraintWithItem:v attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft Multiplier: 1.0 f constant: 20]]; [self.view addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeTop RelatedBy: NSLayoutRelationEqual toItem: self. The view attribute: NSLayoutAttributeTop multiplier: 1.0 f constant: 100]]. [self.view addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeHeight RelatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 f constant: 170]]. UIView* w=v; {// Note that in addition to setting the width and height constraints, the child view also sets the edge constraints relative to the parent view. UIView* v=[[UIView alloc] init]; UIView* v=[[UIView alloc] init]; [w addSubview:v]; v.backgroundColor=[UIColor greenColor]; v.translatesAutoresizingMaskIntoConstraints=NO; [w addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeLeft Attribute relatedBy: NSLayoutRelationEqual toItem: w: NSLayoutAttributeLeft multiplier: 1.0 f constant: 10]]; [w addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeRight Attribute relatedBy: NSLayoutRelationEqual toItem: w: NSLayoutAttributeRight multiplier: 1.0 f constant: - 10]]. [w addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual Attribute toItem: w: NSLayoutAttributeTop multiplier: 1.0 f constant: 10]]; [v addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeHeight RelatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 f constant: 150]]. [v addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeWidth RelatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 f constant: 150]]. }}Copy the code

About scope constraints

NSLayoutRelationGreaterThanOrEqual and NSLayoutRelationLessThanOrEqual is a range of constraints, so on the basis of the scope of this constraint, you can also add other constraint, further restrictions. The end result, then, is that as long as these constraints don’t conflict, you get scopes.

- (void)viewDidLoad { [super viewDidLoad]; _containerView.layer.masksToBounds = YES; _containerView. Layer. BorderWidth = 1.0 f; _containerView.layer.borderColor = [UIColor redColor].CGColor; self.tipLabel.text = @"tutuge.me\niOS"; [_containerView addSubview:self.tipLabel]; [_tipLabel sizeToFit]; [_tipLabel mas_makeConstraints:^(MASConstraintMaker *make) { 1000 make priority. Left. GreaterThanOrEqualTo (_containerView. Mas_left); make. Right. LessThanOrEqualTo (_containerView. Mas_right);  make.top.greaterThanOrEqualTo(_containerView.mas_top); make.bottom.lessThanOrEqualTo(_containerView.mas_bottom); _leftConstraint = make.centerx.equalto (_containerView.mas_left).with.offset(50).priorityHigh(); // The priority is lower than the boundary condition _topConstraint = make.centery.equalto (_containerView.mas_top).with.offset(50).priorityHigh(); // The priority is lower than the boundary condition make.width.mas_equalTo(CGRectGetWidth(_tipLabel.frame) + 8); // make.height.mas_equalTo(CGRectGetHeight(_tipLabel.frame) + 4);}]; / / this constraint ensures UILabel the size of the size of its content. [_tipLabel setContentHuggingPriority: UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; [_tipLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panWithGesture:)]; [_containerView addGestureRecognizer:pan]; } #pragma mark - Pan gesture - (void)panWithGesture:(UIPanGestureRecognizer *)pan { CGPoint touchPoint = [pan locationInView:_containerView]; _logLabel.text = NSStringFromCGPoint(touchPoint); _leftConstraint.offset = touchPoint.x; _topConstraint.offset = touchPoint.y; }Copy the code

  1. In the following constraints, we want viewToAdd to be as large as possible:
    [self.scrollViewContainer addConstraints:[NSLayoutConstraint 
         constraintsWithVisualFormat:@"H:|-(>=32)-[viewToAdd(<=576)]-(>=32)-|" 
                             options:0 
                             metrics:nil  
                               views:NSDictionaryOfVariableBindings(viewToAdd)
    ]];
Copy the code

The above constraint does not meet this requirement. The correct constraint is:

"H:|-(>=32,==32@900)-[viewToAdd(<=576)]-(>=32,==32@900)-|"
Copy the code

ref: Using autolayout on iOS how can I specify that a view should take up as much space as possible?


About the camera permission application in SWIFT

  • All objects have 750,750 as their Content Compression Resistance Priority.
  • The majority has 250,250 as their Content Hugging Priority.
  • UIImageView and UILabel both have 251,251 as their Content Hugging Priority.
  • UIActivityIndicatorView, UIStepper, and UISwitch have 750,750 as their Content Hugging Priority.
  • UIProgressView has 250,750 as its Content Hugging Priority.

Ref: stackoverflow.com/questions/3…

About the camera permission application in SWIFT

AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; if(authStatus == AVAuthorizationStatusDenied){ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil Message :@" Please go to [Settings] to open [Home Doctor - Resident] camera access "Delegate :self cancelButtonTitle:@" Confirm" otherButtonTitles:nil, nil] [alertView show]; return; } [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { if (granted) { } else { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil Message :@" Please go to [Settings] to open [Home Medical-resident] microphone access "delegate:self CancelButtonTitle :@" Ok "otherButtonTitles:nil, nil]; [alertView show];}}];Copy the code

Make sure to:

import AVFoundation
Copy the code

The Swift code below checks for all possible permission states:

Swift 3

let cameraMediaType = AVMediaTypeVideo let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType:  cameraMediaType) switch cameraAuthorizationStatus { case .denied: break case .authorized: break case .restricted: break case .notDetermined: // Prompting user for the permission to use the camera. AVCaptureDevice.requestAccess(forMediaType: cameraMediaType) { granted in if granted { print("Granted access to \(cameraMediaType)") } else { print("Denied access to \(cameraMediaType)") } } }Copy the code

Swift 2

let cameraMediaType = AVMediaTypeVideo
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(cameraMediaType)

switch cameraAuthorizationStatus {
case .Denied: break
case .Authorized: break
case .Restricted: break

case .NotDetermined:
    // Prompting user for the permission to use the camera.
    AVCaptureDevice.requestAccessForMediaType(cameraMediaType) { granted in
        if granted {
            print("Granted access to \(cameraMediaType)")
        } else {
            print("Denied access to \(cameraMediaType)")
        }
    }
}
Copy the code

As an interesting side note, did you know that iOS kills the app if it’s running while you change its camera permissions in Settings? See this developer forum discussion (needs registration).

The system actually kills your app if the user toggles your app’s access to camera in Settings. The same applies to any protected dataclass in the Settings->Privacy section.

Ref:stackoverflow.com/questions/2…


About the presentation of the Action sheet

UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@" DestructiveButtonTitle: nil otherButtonTitles: @ "signing residents," @ "consultation referrals," @ "medical appointments," nil]; actionSheet.actionSheetStyle = UIBarStyleDefault; [actionSheet showFromTabBar:self.tabBarController.tabBar];Copy the code

About the use of NSProgress

1. Notes on NSProgress:

NSProgress object is thread related objects, when [1] the progress becomeCurrentWithPendingUnitCount: is called, that this progress will be the object of the current progress of the current thread. So when we create an NSProgress object progress1 on the current thread, progress1 automatically becomes a child of Progress.

[progress becomeCurrentWithPendingUnitCount: 1] / / generate another progress, to complete the task [the progress resignCurrent] when calling [progress ResignCurrent], then the pending unit cound above is marked as completedCopy the code

2. When we want to assign tasks to different threads, we call NSProgress’s addChild method, which is IOS9+ enabled.

// Multitask reporting progress

- (void)viewDidLoad { [super viewDidLoad]; NSProgress* progress=[NSProgress progressWithTotalUnitCount:-1]; self.progress.observedProgress=progress; [progress becomeCurrentWithPendingUnitCount:100]; [self doWork:^{ NSLog(@"work done"); } progress:progress]; [progress resignCurrent]; } -(void)doWork:(void(^)(void))handler progress:(NSProgress*)mainProgress{ NSProgress* childProgress=[NSProgress progressWithTotalUnitCount:-1]; NSProgress* childProgress1=[NSProgress progressWithTotalUnitCount:-1]; mainProgress.totalUnitCount=100; childProgress.totalUnitCount=50; childProgress1.totalUnitCount=50; [mainProgress addChild:childProgress1 withPendingUnitCount:50]; [mainProgress addChild:childProgress withPendingUnitCount:50]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ for(int i=0; i<100; I++) {[NSThread sleepForTimeInterval: 0.05]; NSLog(@"progress%d",i); ChildProgress.com pletedUnitCount = (I + 1)/(100.0) * 50. }}); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ for(int i=0; i<100; I++) {[NSThread sleepForTimeInterval: 0.09]; NSLog(@"progress1:%d",i); ChildProgress1.com pletedUnitCount = (I + 1)/(100.0) * 50. }}); }Copy the code

/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

- (void)viewDidLoad { [super viewDidLoad]; NSProgress* progress=[NSProgress progressWithTotalUnitCount:-1]; self.progress.observedProgress=progress; / / set the progress into the current thread's current progress [progress becomeCurrentWithPendingUnitCount: 1); [self doWork:^{ NSLog(@"work done"); }]; [progress resignCurrent]; } -(void)doWork:(void(^)(void))handler{ NSProgress* mainProgress=[NSProgress currentProgress]; // Note that child progress and main progress must be in the same thread. NSProgress* childProgress=[NSProgress progressWithTotalUnitCount:-1]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ (void) {/ / initialization completes, update the progress of attributes can be in different threads. MainProgress. TotalUnitCount = 1; childProgress.totalUnitCount=50; for(int i=0; i<100; I++) {[NSThread sleepForTimeInterval: 0.05]; ChildProgress.com pletedUnitCount = (I + 1)/(100.0) * 50. } handler(); }); }Copy the code

NSProgress – Ole Begemann www.tuicool.com/articles/7z…


About off-screen rendering

Self.layer. cornerRadius = 6; self.layer.cornerRadius = 6; self.layer.masksToBounds = YES; / / cut out self. Layer. ShouldRasterize = YES; / / cache the self. Layer. RasterizationScale = [UIScreen mainScreen]. Scale;Copy the code

ShouldRasterize may be turned on to cache layers that draw slowly (like rounded corners) when optimising performance, but this will cause the image to be not sharp on retina screens. You need to set up the self. Layer. RasterizationScale = [UIScreen mainScreen]. Scale;


Set the layout subview bounds

-(void)layoutSubviews{ [super layoutSubviews]; if(_cview==nil){ _cview=[[UIView alloc] init]; [self addSubview:_cview]; / / the following practice, most of the time is right, but sometimes, the client may be manually invoked the setNeedsLayout, layoutIfNeed, lead to the following the self. The bounds is not final rendered bounds, problems will occur. The solution, then, is to put the following code outside the if block. CGRect r=self.bounds; r.origin.y=31; r.size.height=r.size.height-r.origin.y; _cview.frame=r; }}Copy the code

The default implementation of isEqual

The default NSObject implementation of isEqual: simply checks for pointer equality.

The answer about default implementation of isEqual: is comprehensive one. So I just add my note about default implementation of hash. Here it is:

-(unsigned)hash {return (unsigned)self; }Copy the code

I.e it’s just the same pointer value which is used in isEqual:. Here’s how you can check this out:

NSObject *obj = [[NSObject alloc] init];
NSLog(@"obj: %@",obj);
NSLog(@"hash: %lx",obj.hash);  
Copy the code

Output:

obj: <NSObject: 0x7fcfb2f257c0>
hash: 7fcfb2f257c0
Copy the code

UIScrollView proxy method

UIScrollView’s proxy methods are mainly divided into two kinds, one is related to user drag, one is related to sliding deceleration

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {// NSLog(@"%s", __PRETTY_FUNCTION__); } / / users started dragging, call this method - (void) scrollViewWillBeginDragging (scrollView UIScrollView *) {NSLog (@ "% s", __PRETTY_FUNCTION__); [self logDraggingAndDecelerating]; }Copy the code

//// This method, introduced from iOS 5, is called before didEndDragging, when velocity in the willEndDragging method is CGPointZero (no speed in either direction at the end of dragging), Activity ATE in didEndDragging is NO, i.e. there is NO deceleration, will begin and didendating will not be invoked. Conversely, when Velocity is not CGPointZero, the Scroll view starts with Velocity and slows down until targetContentOffset. It’s worth noting that targetContentOffset here is a pointer, and yes, you can change the destination of the deceleration movement, which is useful for some effects,

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { NSLog(@"%s velocity: %@, targetContentOffset: %@", __PRETTY_FUNCTION__, [NSValue valueWithCGPoint:velocity], [NSValue valueWithCGPoint:*targetContentOffset]); [self logDraggingAndDecelerating]; } / / the end of the user drag, call this method, if decelerate to zero, then the scroll will immediately stop. - (void) scrollViewDidEndDragging: (scrollView UIScrollView *) willDecelerate:(BOOL)decelerate { NSLog(@"%s --> willDecelerate:%d", __PRETTY_FUNCTION__,decelerate); [self logDraggingAndDecelerating]; } // The deceleration animation is called before it starts. - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { NSLog(@"%s", __PRETTY_FUNCTION__); [self logDraggingAndDecelerating]; } // When the deceleration animation ends, there is a special case: When dragging the Scroll view again before a deceleration animation ends, didEndDecelerating will not be invoked, and the Dragging Scroll view dragging and Decelerating attribute are both YES. New dragging, if accelerated, will begin activity will be invoked again, and then didendactivity; If there's no acceleration, you're not going to call willBegin Activity, but you're going to call didendactivity,  - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { NSLog(@"%s", __PRETTY_FUNCTION__); [self logDraggingAndDecelerating]; }Copy the code
  1. When continuously scrolling through UIScrollView, the order in which the agents are called may be as follows. Note the order in which the agents are called:

First drag related, then deceleration related.

scrollViewWillBeginDragging: 
scrollViewWillEndDragging: withVelocity: targetContentOffset: 
scrollViewDidEndDragging: willDecelerate: 
scrollViewWillBeginDecelerating: 
scrollViewWillBeginDragging: 
scrollViewWillEndDragging: withVelocity: targetContentOffset: 
scrollViewDidEndDragging: willDecelerate: 
scrollViewWillBeginDecelerating: 
...
scrollViewWillBeginDragging: 
scrollViewWillEndDragging: withVelocity: targetContentOffset: 
scrollViewDidEndDragging: willDecelerate: 
scrollViewWillBeginDecelerating: 
scrollViewDidEndDecelerating:
Copy the code
  1. Dragging, YES, and decelerating, NO. Decelerate, dragging and decelerating are both YES. Activity will start the next drag before it ends, dragging and decelerating are both STILL YES. Therefore, table View dragging and Decelerating cannot be used to determine whether the user is dragging or decelerating.

This is easily resolved by adding a variable such as userDragging, set to YES in willBeginDragging and NO in didEndDragging.

When UIScrollView scrolling stops:

It’s a common requirement for an application to know when a user stops scrolling aUIScrollView. There is the obvious delegate, scrollViewDidEndDecelerating, method that announces when a scroll view stops moving. However, this will only fire if the UIScrollView diddecelerate to a stop. It won’t fire if a user carefully scrolls to a spot without creating any momentum. To cover all the bases, you need to also listen to scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate for instances where the user stopped dragging and the UIScrollView also stopped without accelerating.

- (void) scrollViewDidEndDragging: (UIScrollView *) scrollView willDecelerate: (BOOL) decelerate {/ / without slowing down to stop the if (! decelerate) [self postScrollExplosion:scrollView]; } - (void) scrollViewDidEndDecelerating: (scrollView UIScrollView *) {/ / in the case of slow stop [self postScrollExplosion: scrollView]; }Copy the code

If will decelerate argument is false, then we know the UIScrollView stopped scrolling.


Outlets of Interface Builder should be strong or weak

The outlets of the interface Builder are called strong, but the outlets of the Interface Builder are called weak. The outlets of the Interface Builder are called strong

The current recommended best practice from Apple is for IBOutlets to be strong unless weak is specifically needed to avoid a retain cycle. As Johannes mentioned above, this was commented on in the “Implementing UI Designs in Interface Builder” session from WWDC 2015 where an Apple Engineer said: And the last option I want to point out is the storage type, which can either be strong or weak. In general you should make your outlet strong, especially if you are connecting an outlet to a subview or to a constraint that’s not always going to be retained by the view hierarchy. The only time you really need to make an outlet weak is if you have a custom view that references something back up the view hierarchy and in general that’s not recommended. I asked about this on Twitter to an engineer on the IB team and he confirmed that strong should be the default and that the developer docs are being updated.

Twitter.com/_danielhall…

Summarized from the developer library: From a practical perspective, in iOS and OS X outlets should be defined as declared properties. Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create will therefore typically be weak by default, because:

  • Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, are arbitrary references between objects that do not imply ownership.

  • The strong outlets are frequently specified by Framework classes (for example, UIViewController’s View outlet, The or NSWindowController ‘s window outlet).

      @property (weak) IBOutlet MyView *viewContainerSubview;
      @property (strong) IBOutlet MyOtherClass *topLevelObject;
    Copy the code

Stackoverflow.com/questions/7…


A newline in macro expansion

#define AA(x) #x @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSString* s= @AA(dfa sdf kds fsf); Dfa SDF KDSFSF}Copy the code

KVO for text in UITextView

Because inside the UITextView, when you type text, it’s not called setText, it’s computed directly. So when you enter text in UITextView, the following listener doesn’t work. However, when you call the [UITextView setText:] method, the following KVO can be heard.


About the Status Bar font and background colors

UIViewControllerBasedStatusBarAppearance actual role is as follows: this attribute only affects how to set the status bar on the font color is black or white, the background color of the status bar. The background color of the status bar is always transparent on iOS7. Therefore, the background color of the Status bar is the color of the view on the top layer, and the background color of the Navigation bar when there is a Navigation bar. when

When UIViewControllerBasedStatusBarAppearance = NO: UIApplication setStatusBarStyle method into effect:  [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; ViewController's preferredStatusBarStyle method is invalid:  - (UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent; } UIViewControllerBasedStatusBarAppearance = YES: when the UIApplication setStatusBarStyle is null and void. UINavigationviewController preferredStatusBarStyle method is effective. To be precise, the preferredStatusBarStyle method of the first viewController loaded is validCopy the code

With IOS7, Windows expands across the screen, and the status bar floats on top.

When a UINavigationController is present, the UINavigationBar will automatically be placed below the status bar (the standard 20 point offset from the top of the screen that we are accustomed to from previous iOS versions). The background of the status bar will be modified to match the UINavigationBar below it. `The status bar will inherit the color and transparency of the UINavigationBar.Additionally


Stop the UISearchDisplayController full screen

If the current in the VC NavigationBar, UISearchDisplayController will automatically hide the UINavigationBar, and automatically full-screen.

/ / in the subclass of UISearchDisplayController rewrite the following method - (void) setActive (BOOL) visible animated (BOOL) animated; { if(self.active == visible) return; [self.searchContentsController.navigationController setNavigationBarHidden:YES animated:NO]; [super setActive:visible animated:animated]; [self.searchContentsController.navigationController setNavigationBarHidden:NO animated:NO]; if (visible) { [self.searchBar becomeFirstResponder]; } else { [self.searchBar resignFirstResponder]; }}Copy the code

Use Instruments to view retain Cycle

In allocation, you check the objects that belong to your project and iterate to see if there are any objects that should be released but are not.

I just transitioned an older app to use ARC. Instruments showed no leaks, but the allocations continued to go up. I found that by looking at the live objects for something that I knew should be deleted, I was able to track down the retains without a release. Here are the basic steps:

  1. Use the Allocations tool in Instruments
  2. Play with your app for a while (if you know what isn’t being released, this goes faster)
  3. Change Statistics to Objects in the Allocations jump bar
  4. Sort by Category and find the class name of your unreleased object
  5. Find a living instance and click the little right arrow next to the memory address
  6. Now you can see the history of retains and releases for an object

Stackoverflow.com/questions/9…


Default location for NSTextAttachment

NSTextAttachment * textAttachment = [[ NSTextAttachment alloc ] initWithData:nil ofType:nil ] ; UIImage * image = [ UIImage imageNamed:@"a.jpg" ]; //my emoticon image named a.jpg textAttachment.image = image ; TextAttachment. Bounds = CGRectMake (0, 0, 8, 8).Copy the code

The following information is displayed :extAttachment The Origin point displayed is above the baseline.

Compare the following figure:

If you want the image to be centered, you have to do something like this:

NSTextAttachment * textAttachment = [[ NSTextAttachment alloc ] initWithData:nil ofType:nil ] ; UIImage * image = [ UIImage imageNamed:@"a.jpg" ]; //my emoticon image named a.jpg textAttachment.image = image ; UIFont* font=[UIFont boldSystemFontOfSize:40]; TextAttachment. Bounds = CGRectMake(0, (mid-10/2.0)/2.0f, 10,10);Copy the code


Rules about NSKeyedArchiver

  1. mydata=[NSKeyedArchiver archivedDataWithRootObject:thing1]; // Suppose Thing1 implements the NSCoding protocol
  2. thing1=[NSKeyedUnarchiver unarchivedObjectWithData:mydata];

What happens is simple: you use the archivedDataWithRootObject() method of NSKeyedArchiver, which turns an object graph into an NSData object, then write that to NSUserDefaults as if it were any other object. If you were wondering, “object graph” means “your object, plus any objects it refers to, plus any objects those objects refer to, and so on.”

The rules are very simple:

  1. All your data types must be one of the following: boolean, integer, float, double, string, array, dictionary, NSDate, or a class that fits rule 2.
  2. If your data type is a class, it must conform to the NSCoding protocol, which is used for archiving object graphs.
  3. If your data type is an array or dictionary, all the keys and values must match rule 1 or rule 2.

About the use of Weakify and Strongify

@weakify(self)
[[self.searchText.rac_textSignal
  map:^id(NSString *text) {
      return [UIColor yellowColor];
  }]
 subscribeNext:^(UIColor *color) {
     @strongify(self)
     self.searchText.backgroundColor = color;
 }];
Copy the code

code after preprocess:

@autoreleasepool {} __attribute__((objc_ownership(weak))) __typeof__(self) self_weak_ = (self); [[self.searchText.rac_textSignal map:^id(NSString *text) { return [UIColor yellowColor]; }] subscribeNext:^(UIColor *color) { @try {} @finally {} __attribute__((objc_ownership(strong))) __typeof__(self) self = self_weak_; // 1 self.searchText.backgroundColor = color; //2 }]; 1: define a new local variable "self". This will shadow the global one. So here we used the local variable "self" --self_weak_. Tips: 1.if we used self.xxx in block, we should place @strongify(self) over it. 2.don't forget use @weakify(self) to define the variable self_weak_.Copy the code

PS: I’m trying to learn English. I hope that you can understand what I’m saying.

Ref: stackoverflow.com/questions/2…


Add different callbacks to UIButton

- (void)viewDidLoad {
    [super viewDidLoad];
     [_btn addTarget:self action:@selector(addBtnClicked) forControlEvents:UIControlEventTouchUpInside];
     [_btn addTarget:self action:@selector(addBtnClicked1) forControlEvents:UIControlEventTouchUpInside];
}

-(void)addBtnClicked{
    NSLog(@"addBtnClicked");
}

-(void)addBtnClicked1{
    NSLog(@"addBtnClicked");
}
Copy the code

UUID scheme


UITableViewCell dynamic height

// Compute the preferredMaxLayoutWidth value of UILabel, which must be set for multiple lines, Label. preferredMaxWidth = [UIScreen mainScreen].bounds.size. width-margin-padding; Manually calculating the width feels like a throwback to the days without Autolayout =. =Copy the code

About using UITextField in UITableViewCell

When using a UITextField in a UITableViewCell, be sure to set [self.view endEditing:YES] when submitting otherwise you may not get the latest value


About the use of custom Views in UITableViewCell

  1. When it’s first displayed, when it’s loaded, how should it be displayed, notice that the layoutSubview is going to be called

  2. When the cell is reused. In other words, when the cell created above is reused and loaded with different or the same data again, how should it be displayed

  3. If the height of a cell needs to change dynamically, feedback reloadData in time when data changes. In general, when the height changes, store the height in a dictionary with IndexPath as the key and reloadData.

  4. NSIndexPath can’t be used as a Key directly, it has to be converted to a string before it can be used as a Key


About UITextView

1. The height of UITextView is calculated as follows: textView.contentSize.height+textView.textContainerInset.top+_textView.textContainerInset.bottom. TextView. TextContainerInset value generally as follows: [8 0 0]

2.UITextView updates its contentOffset as its contents change.

3.UITextView also updates its contentOffset after keyboard dismiss. Generally, the content inside will scroll to the top. The call stack is as follows: layoutSubview -> updateContentSize -> setContentOffset

4. When scrollEnabled of UITextView is set to NO, the frame change may be inaccurate. Set userInterfaceEnabled of UITextView to NO if allowed. To disable scrolling

5. Using a UITextView in a UITableViewCell can be difficult if it is height and keyboard adaptive. Preferably in a new page edit.


About the hash

In general, when you override the method isEqual:,

When an object is used as a key, its hash method is called to generate a unique identifier. NSDictionary needs to look up objects based on unique keys (values generated by the hash algorithm), and NSSet needs to look up objects based on hash values to ensure that duplicate objects are filtered out. When used as a key in an NSMutableDictionary, the hash method executes but crashes because the Model class doesn't implement the NSCopying protocol. When creating an immutable array, the Model as a key executes the hash method but also crashes. Because the Model class does not implement NSCopying protocol Model * Model = [Model new]; NSDictionary *dictionary = @{model : @"A"}; dictionary = nil; When the dictionary executes setObject:forKey:, it executes the hash method on the key to generate a key, and then copies the key. The addObject: method of set performs the following process: first obtains the hash value of object modelA, then obtains the hash value of object modelB when adding modelB, and then compares it. If the comparison results are consistent, it is considered the same object.Copy the code

About the URL Schemes

Set the following in an app:

In another app, running the following code will open the corresponding app above:

 [[UIApplication sharedApplication] openURL:[NSURL RLWithString:@"cloud://me.me.venj.myapp-ios"]];
Copy the code

Register custom URL scheme-Cocoa learning in Mac and iOS


About escaping in IOS regular expressions

Today, I helped my friend to solve this problem. Json returns are all with “”, so I need to remove the backslash, but the “” in OC is an escape character, can not be directly expressed by @””, after a search, I found the representation method of OC to escape characters, as follows:

\ A - Sound alert \ B - backspace \ F - Form feed \ N - Newline \ R - Carriage return \ T - horizontal TAB \ V - Vertical TAB \\ - backslash \" - double quotes \' - single quotesCopy the code

So in IOS regular expressions,\w stands for a letter, but when written, it should be written as “\w”. In general, it should not be used directly, because it and the character after it represent escape. The \ character used in the re, so the use of \[] has special meaning. To use it literally, write “\[“.

Content Hugging priority and Content Compression Resistance Priority Priority: When Content is compressed, Content with a higher priority will not be compressedCopy the code

Look at an example from StackOverflow: Now you have a button like this [Click Me] that has its horizontal constraints set to the superview, and the constraints have a priority of 500 (set to 500 just for convenience, default is 1000), Then set the button’s horizontal Content priority (Both Content Hugging and Content Compression Resistance), and the effect will vary according to its horizontal Content priority. Look at the Content Hugging priority first. If the superview wants to grow at this point, the button will look like this [Click Me] (I don’t want to stretch) when Content Hugging priority becomes bigger than 500. When less than 500 it does this [Click Me] (then the superview is elongated);

And Content Compression Resistance priority, if the superview is now going to shrink, when Content Compression Resistance priority is greater than 500, This button will do this [Click Me] (I don’t want to be squeezed) when less than 500 [Cli…] (Then the superview is squeezed)


Difference between RACSignal and RACSequence

One is pull driven (RACSequence) and the other is push driven (RACSignal). From here: Push-driven means that values for the signal are not defined at the moment of signal creation and may become available at a later time (for example, as a result from network request, or any user input). Pull-driven means that values in the sequence are defined at the moment of signal creation and we can query values from the stream one-by-one. In your case, you make the RACSignal pull-driven, because you are already have its values.


Calculates the number of lines of text

Listing 1 Counting hard line breaks

NSString *string;

unsigned numberOfLines, index, stringLength = [string length];

for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++)
    index = NSMaxRange([string lineRangeForRange:NSMakeRange(index, 0)]);
Copy the code

Listing 2 Counting lines of wrapped text

NSLayoutManager *layoutManager = [textView layoutManager];
unsigned numberOfLines, index, numberOfGlyphs =
        [layoutManager numberOfGlyphs];

NSRange lineRange;
for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
  (void) [layoutManager lineFragmentRectForGlyphAtIndex:index
           effectiveRange:&lineRange];
   index = NSMaxRange(lineRange);
}
Copy the code

Ref:developer.apple.com/library/mac…


The different UICollectionView

// One difference between UICollectionView and UITableView

UICollectionViewLayoutAttributes *attributes = [self.collectionView.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath];


UICollectionView scrolls to the specified position.

UICollectionViewLayout already provides two methods to do this:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset NS_AVAILABLE_IOS(7_0);
Copy the code

It can also be done by proxy:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset 
Copy the code

Ref:www.cnblogs.com/Phelthas/p/…


About UICollectionViewFlowLayout

// Using attributes is better than using cells, Because the cell because is beyond the scope of the screen may cause cellForItemAtIndexPath returns nil UICollectionViewLayoutAttributes * attributes = [self.collectionView.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath];Copy the code

1. Avoid image mapping errors caused by cell reuse during asynchronous loading

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { BHAlbumPhotoCell *photoCell = [collectionView dequeueReusableCellWithReuseIdentifier:PhotoCellIdentifier forIndexPath:indexPath]; BHAlbum *album = self.albums[indexPath.section]; BHPhoto *photo = album.photos[indexPath.item]; // load photo images in the background __weak BHCollectionViewController *weakSelf = self; NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ UIImage *image = [photo image]; dispatch_async(dispatch_get_main_queue(), ^ {/ / when the cell is still visible, the asynchronous loading success, normal corresponding cell. UITableView has the same method. The if ([weakSelf. CollectionView. IndexPathsForVisibleItems containsObject:indexPath]) { BHAlbumPhotoCell *cell = (BHAlbumPhotoCell *)[weakSelf.collectionView cellForItemAtIndexPath:indexPath]; cell.imageView.image = image; } }); }]; operation.queuePriority = (indexPath.item == 0) ? NSOperationQueuePriorityHigh : NSOperationQueuePriorityNormal; [self.thumbnailQueue addOperation:operation]; return photoCell; }Copy the code

About UICollectionViewFlowLayout

1. The UICollectionView calls the following method, which rearranges the visible cells

- (void)performBatchUpdates:(void (^(void))updates completion:(void (^)(BOOL finished))completion;
-(void)reloadData;
Copy the code

2. Layout order:

A. If the cell size is fixed, go to the next step. Otherwise, call: - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout SizeForItemAtIndexPath :(NSIndexPath *) to get the size B of the cell. Call UICollectionViewFlowLayout prepareLayout to prepare layout, here you can make some preparations for C. Call - (NSArray *) layoutAttributesForElementsInRect: (CGRect) the rect to set the each current show that the cell size, level, the transform and so on, at the same time, This method can also set the layout properties of the Supplement View and decorationView. The only way to use this method properly is not to return all of the attributes, unless the view is within the viewable range of the current collectionView, or the user experience is degraded by a lot of extra computationCopy the code

3. Something else

A. Because the collectionView delegates the layout task of the Item to the Layout object, the size of the scroll area is unknown to the collectionView. Custom layout objects must be counted in this method to display contents, including supplementaryView and decorationView. - (CGSize)collectionViewContentSize B. Very important method. The collectionView may request special layout attributes for specific items. We can create and return custom layout attributes in this method. According to the incoming indexPath call [UICollectionViewLayoutAttributes layoutAttributesWithIndexPath: ] method to create a property object, and then set the created properties, Including animation effects such as custom deformation, displacement - (UICollectionViewLayoutAttributes *) layoutAttributesForItemAtIndexPath indexPath C: (NSIndexPath *). When the Bounds of the collectionView change, we need to tell the collectionView whether the layout property needs to be recalculated, and this method returns the result of recalculation. Simply returning YES would cause our layout to be constantly redrawn every second, causing additional computation. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBoundsCopy the code

4. Issues for attention:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath Row does not represent a row, as in UITableView indexpath. row represents a single rowCopy the code

5. Decoration must be registered in UICollectionViewFlowLayout view.

Register the emblem view at the end of the setup method on BHPhotoAlbumLayout:

[self registerClass:[BHEmblemView class] forDecorationViewOfKind:BHPhotoEmblemKind];
Copy the code

Unlike the other views we’ve added, only the layout class deals with decoration views, thus we perform the registration here rather than in the view controller.

6. PrepareForReuse in a subclass of UICollectionViewCell to clean up before reuse

- (void)prepareForReuse
{
    [super prepareForReuse];
    self.imageView.image = nil;
}
Copy the code

Ref:www.cnblogs.com/Phelthas/p/…

7. Some concepts of UICollectionView

Supplementary views are usually used to provide extra information about a section within the collection view, effectively replacing the concept of header and footer views in a table view.

Decoration views are used to provide visual ornamentation to the collection view (for example, a background image behind a section, or an ornamental icon at the end of the collection view).

Both supplementary and decoration views must be subclasses of UICollectionReusableView.

8. UICollectionViewUpdateItem when its item attribute for NSNotFound said this is a section view

An instance of UICollectionViewUpdateItem can represent either an item or a section update, and the only way to tell which is that update items which represent section updates contain index paths with a valid section index and NSNotFound for the item index, while update items that represent item updates contain index paths with valid item indexes.

  if (updateItem.indexPathAfterUpdate.item == NSNotFound)
   {
    [self.insertedSectionIndices addObject:@(updateItem.indexPathAfterUpdate.section)];
   }
Copy the code

ref:Animating Items in a UICollectionView

8. Batch update UICollectionView animations. Just like UITableView, you put insert, delete, update statements in their place.

NSMutableArray* indexArray=[[NSMutableArray alloc] init]; NSInteger count=_imgDataArray.count; for(NSInteger i=0; i<photos.count; i++){ [indexArray addObject:[NSIndexPath indexPathForRow:count+i inSection:0]]; } [self->_imgDataArray addObjectsFromArray:photos]; dispatch_async(dispatch_get_main_queue(), ^ {[UIView animateWithDuration: delay 0.5:1 usingSpringWithDamping: initialSpringVelocity 0.5:1 options:UIViewAnimationOptionCurveEaseIn animations:^{ [self->_imgCollectionView performBatchUpdates:^{ [self->_imgCollectionView insertItemsAtIndexPaths:indexArray]; } completion:^(BOOL b){ }]; } completion:^(BOOL b){ [self->_imgCollectionView reloadData]; }]; });Copy the code

Button sets titleEdgeInsets and imageEdgeInsets to adjust its image and label positions relative to each other

Premise: This is when the frame of the button is sufficient to display the image and label content. If the frame is insufficient, the image or text will be compressed (the demo button is drawn on the XIB, so the size is just right)

TitleEdgeInsets are the insets of the title relative to the top, bottom, left, and right of the tableView, similar to the contentInset of the tableView. If you only have the title, it is relative to the top, bottom, left, and right of the button. If there are both image and label, the upper and lower left of the image is relative to the button, and the right is relative to the label. The top right bottom of the title is relative to the button, and the left is relative to the image. The following figure

Note these two properties:

ref: www.cnblogs.com/Phelthas/p/… Stackoverflow.com/questions/4…