Ios Programming 4th edition random thoughts, random thoughts

The object of an OC can be thought of as a command center, controlling various parts of memory. It’s like a net. The structure of linked list is adopted.

Object directly holds instance variables of non-pointer type.

Sending a message to super is actually sending a message to self, but requires the system to skip the current object’s class and start the query from the parent class when looking for methods.

In initialization methods, instance variables should be accessed directly. In other methods, access methods are used.

Any class, no matter how many initializers there are, must select one of them as the designated initializer. Specifying the initialization method ensures that each instance variable of the object is in a valid state.

The mechanism of using initialization methods in tandem reduces errors and makes it easier to maintain code. When creating a class, you need to identify the specified initialization method first, and then the core code that writes the initialization in the specified initialization method. Other initialization methods simply call the specified initialization method (directly or indirectly) and pass in the default values.

Summary of initialization methods

  • A class inherits all of its parent class’s initializers, or can add any number of initializers to the class.
  • Each class selects a designated initialization method.
  • The specified initialization method of the parent class must be called with the specified initialization method before any other initialization work can be performed. (directly or indirectly)
  • Other initialization methods call the specified initialization method (directly or indirectly).
  • If a class’s designated initializer differs from its parent, it must override the parent’s designated initializer and call a new designated initializer (directly or indirectly).

The order in which header files are declared instance variable declarations should come first, followed by the class methods, followed by the initialization methods, and finally the other methods.

A class method can be called a convenience method if its return type is an object of the class.

Any property has three properties:

  • Multithreaded feature (nonatomic, atomic), atomic by default;
  • The read/write feature (readwrite, readonly) is readwrite by default;
  • Across memory management, such as strong, weak, copy, and unsafe_unretained. The default value is strong, and the default value of non-object attributes is unsafe_unretained.

In general, when an attribute is a pointer to another object and the object’s class has modifiable subclasses (such as NSString/NSMutableString), you should set the attribute’s memory management feature to copy. Here’s why:

  • The property may point to an object whose class has a modifiable subclass. The subclass object may be modified without the owner’s knowledge. Therefore, it is best to copy the object first.
  • Sending a copy to an immutable object returns a pointer to itself. No memory space is wasted.

When a save or fetch method is overridden for a declared property, the compiler does not automatically generate the method and instance variables.

View controller

View controllers create view hierarchies in two ways:

  • Code: override loadView in UIViewController
  • Nib file: Use Interface Builder to create a Xib file, add the required view hierarchy, and the view controller will load the Nib file compiled from the Xib file at run time

Declaring socket variables as weak references is a programming convention. When the available memory of the system is low, the view controller automatically frees its view and creates it later when it needs to be displayed. To free all of the view’s child views at the same time as the view is freed, thus avoiding a memory leak.

Socket variables that point to a top-level object in a XIB file must be declared strong references, whereas weak references should be used when socket variables point to an object owned by the top-level object (such as a child view of the top-level object).

Lazy loading of views To implement lazy loading of views, no child views of the view cargo should be accessed in initWithNibName: Bundle:. Any initialization code associated with a view or its children should be implemented in the viewDidLoad method to avoid loading views that do not need to be displayed on the screen.

The view created in the XIB file should be accessed in the following two methods:

viewDidLoad viewWillAppear

The difference is: If you only need to set the view object once after the app starts, select viewDidLoad. If the user needs to set the view controller’s view every time they see it, select viewWillAppear.

Interact with the controller and its views

  • application:didFinishLaunchingWithOptions:Only called once after the application has started.
  • initWithNibName:bundle:This method is the designated initialization method of UIViewController, which is called when the view controller is created.
  • loadView:You can override this method by setting the view properties of the view controller in code.
  • viewDidLoadYou can override this method, which is called after the view controller has loaded, by setting the view object created with the NIB file.
  • ViewWillAppear: viewDidAppear: viewWillDisappear: viewDidDisappear:These methods will be called many times.

UITableViewController

MVC

  • Model: Stores data, independent of the user interface.
  • View: Is responsible for displaying the interface, independent of the model object.
  • Controller (Controller) : Responsible for ensuring the consistency of data between view objects and model objects.

@class

The @class directive can be used when a file only needs to use a class declaration without knowing the implementation details. The advantage of using this directive is that when the header file of a class changes, the compiler saves compilation time by not recompiling other files that declare the class through the @class directive.

In other files, when a program sends a message to a declared class or object, it must import the class’s header file, and the compiler knows all the implementation details.

Reuse UITableViewCell

Creating a corresponding UITableViewCell object for each record would quickly exhaust the memory resources of an ios device. To solve this problem, you need to reuse the UITableViewCell object. When scrolling, some UITableViewCell objects are removed from the window, and UITableView puts the removed cell objects into the UITableViewCell object pool, waiting for reuse.

By convention, the class name of a UITableViewCell or UITableViewCell subclass should be used as a reuseIdentifier.

The view’s responsibility is to present the data in the model object to the user, and updating the view without updating the model object will result in data inconsistency errors.

The camera

NSDictionary

NSDictionary is very useful, and the most common uses are mutable data structures and query tables.

Mutable data structures: To describe a model object in code, it is common to create a subclass of NSObject and then add the attributes of the model object. ** The difference between using NSDictionary and subclassing NSObject is that subclassing NSObject requires that the attributes of the class be clearly defined in advance and cannot be modified, added to, or removed later. Using NSDictionary will do.

Lookup tables: When you need to write code that contains Dalian if-else or switch statements, you should generally consider replacing it with NSDictionary. Such as:

- (void)changeCharacterClass:(id)sender {
    NSString *enteredText = textField.text;
    CharaterClass *cc = nil;
    
    if ([enteredText isEqualToString:@"Warrior"]) {
        cc = knignt;
    } else if ([enteredText isEqualToString:@"Mage"]) {
        cc = wizard;
    }
    
    character.characterClass = cc;
}
Copy the code

The above code should be replaced with:


NSMutableDictionary *lookup = [[NSMutableDictionary alloc] init];
[lookup setObject:knight forKey:@"Warrior"];
[lookup setObject:wizard forKey:@"Mage"];

- (void)changeCharacterClass:(id)sender {
    
    
    character.characterClass = [lookup objectForKey:textField.text];
}
Copy the code

Handles touch events and creates line objects

Using valueWithNonretainedObject: method will UITouch object memory address encapsulated as NSValue object. The reason for using the memory address to distinguish UITouch objects is that the memory address does not change during the touch event’s start, move, or end. UITouch objects with the same memory address must be the same object.

Why can’t the UITouch object itself be used as a key in an NSMutableDictionary? This is because the keys of NSDictionary and its subclass NSMutableDictionary must comply with the NSCopying protocol — the keys must be copiable (able to respond to copy messages). The UITouch object does not comply with the NSCopying protocol because each touch event is unique and should not be copied.

Chain of response objects:

[image upload failed…(image-4919FC-1509616086734)]

If there is no specific event handling method overridden for a UIResponder object, the nextResponder for that object will attempt to handle the corresponding touch event. It’s eventually passed to UIApplication, and if UIApplication can’t handle it either, the system drops the event.

Introduction to Automatic layout

  • If the views are all first-class child views of the view controller, you can find them all by walking through them once.

- (void)viewDidLayoutSubviews {
    for (UIView *subView in self.view.subviews) {
        if (subView hasAmbiguousLayout) {
            NSLog(@"% @", subView); }}}Copy the code
  • If these views contain complex view hierarchies, another approach should be used:

Add a breakpoint to viewWillAppear and type in the console:

po [[UIWindow keyWindow] _autolayoutTrace]

This method can be used if the application interface layout is not as expected and the cause cannot be determined.

The view controller needs to display a completely different interface for the iPhone and iPad by creating two separate XIB files

XIB files for iPhone and iPad need to be suffixed after the class name:

CZViewController~iphone.xib
CZViewController~ipad.xib
Copy the code

[image upload failed…(image-c2d487-1509616086734)]

[image upload failed…(image-d4d689-1509616086734)]

Use automatic layout in your code

In general, to create a view for UIViewController, override the loadView method if you create an entire view hierarchy and all view constraints; ViewDidLoad is overridden if only a view or constraint is added to the view hierarchy created through the NIB file

Visual Format Language

According to Apple’s naming conventions, you should use the name of the property or the name of the instance variable as the key of the view object. The visual format string represents the corresponding view object using the keys in the dictionary.

Creating and adding constraints in a XIB file can be done in one step, but creating and adding constraints in code requires two separate steps.

NSDictionary *nameMap = @{@"imageView" : self.imageView,
                              @"valueField" : self.valueField,
                              @"toolBar" : self.toolBar
                              };
    NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[imageView]-0-|"
                                            options:0
                                            metrics:nil
                                              views:nameMap];
    NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[valueField]-[imageView]-[toolBar]"
                                                                           options:0
                                                                           metrics:nil
                                                                             views:nameMap];
    
    [self.view addConstraints:horizontalConstraints];
    [self.view addConstraints:verticalConstraints];
Copy the code

How to determine which view the constraint should be added to, here are the rules:

  • If the constraint applies to multiple views with the same parent view at the same time, the constraint should be added to their parent view. (For example, constraint A in the figure below)
  • If the constraint applies to multiple views with different parent views at the same time, but those views have a common ancestor view in the hierarchy, then the constraint should be added to their nearest and closest ancestor views. (For example, constraint C in the figure below)
  • If the constraint only applies to a view itself, then the constraint should be added to that view. (For example, constraint B in the figure below)
  • If the constraint applies to both a view and its parent, the constraint should be added to its parent.

[image upload failed…(image-8181a6-1509616086734)]

(Intrinsic Content Size) Intrinsic Content Size

Inherent content size: The actual size of the content area to be displayed by the view.

The automatic layout system adds constraints to the view based on the inherent content size. Unlike other constraints, these constraints have two priority attributes, There are content magnification priority and Content Compression resistance Priority, respectively.

Content Hugging Priority: Indicates the enlargement priority of the view’s intrinsic content size. If the priority is 1000, it won’t allow the autolayout system to enlarge the view size based on its intrinsic content. On the contrary, if the priority is smaller than 1000, the autolayout system will enlarge the view size when necessary. Content Compression resistance Priority: indicates the reduction priority of the inherent content size of the view. If the priority is 1000, it indicates that the automatic layout system is not allowed to reduce the size of the view based on the inherent content size; Conversely, if the priority is less than 1000, the automatic layout system will reduce the size of the view if necessary.

The relationship between views and controllers

Father and son

When you use a view controller container, you generate a view controller that has a parent-child relationship. Hold a set of viewControllers through viewControllers.

View controller container features:

  • The container object adds the views in viewControllers to its own view as child views.
  • Container view objects usually have their own default appearance.

View controllers in the same parent-child relationship form a family:

  • Any container object can access its children through viewControllers.

  • Child objects can access their container objects through four specific properties of UIViewController objects:

    1. Let’s start with the first three of the four specific attributes:navigationController,tabBarController,splitViewController. When a view controller receives one of these three messages, it looks up the family until it finds a view controller whose type matches. If not found, return nil.
    2. Fourth attribute:parentViewController, which points to the “nearest” container object in the family.

Someone who presents to you or someone who presents to you

A view controller with this relationship is generated when one view controller displays another view controller in modal form. When one view controller A displays another view controller B modally, B’s view overwrites A’s view. This is different from the parent-child relationship introduced earlier, where the child view of the parent-child relationship is only displayed in the view of the container object. When one view controller A displays another view controller B modally, A’s presentedViewController points to B, and B’s presentingViewController property points to A.

[Image upload failed…(image-80AF6A-1509616086734)]

In a display-and-shown relationship, the view controllers at either end of the relationship are not in the same family. The view controller that is displayed will have its own family.

As shown in the figure above, any parent-child property points to an object in the scope of the current family. So sending a UITabBarController object to a view controller in family 2 returns nil.

View controller relationships in different families: When an application displays a view controller modally, it is the top view controller in the related family that is responsible for displaying the view controller. (For example, the presentingViewController properties of the view controller in family 2 point to UITabBarController objects.)

You can write code that changes the behavior of the top object being responsible for displaying other view controllers modally (iPad only). This allows you to restrict where the view is displayed.

Therefore, UIViewController provides definesPresentationContext properties, its default value is NO, when to NO, will pass right to “show” to the parent view controller, and the clan system in turn up, until the top view controller. On the contrary, if in the process of delivery, if a view controller definesPresentationContext is YES, the view controller will no longer pass right to “show” to the parent view controller, but by oneself is responsible for the new view controller. In addition, in this case, the need to display the view controller modalPresentationStyle attribute must be set to UIModalPresentationCurrentContext.

Save, read and apply state

Application sandbox

The application sandbox will contain the following directories:

  • Application Bundles: Contains application executables, such as NIB files.
  • Documents/ : Stores the data generated when the application is running and needs to be retained. This directory is backed up during device synchronization.
  • Library/Caches/ : Store data generated while the application is running that needs to be retained. It doesn’t synchronize.
  • Library/Caches/ : Store all preferences. useNSUserDefaultsClass to store data as key-value pairs from a specific file in the Library/Perferences directory. This directory is backed up during device synchronization.
  • TMP / : stores temporary data required for application running. It doesn’t synchronize. throughNSTemporaryDirectoryThe TMP/function returns the full path to the TMP/directory.

Application status and switching

[image upload failed…(image-314295-1509616086734)]

An application that is not running does not execute any code and does not use RAM. When the application is active:

  • The system is interrupted by a system event and enters the inactive state temporarily. Such events include receiving SMS messages, receiving push messages, and incoming calls.
  • Press the lock button at the top to switch to inactive and leave inactive until the device is unlocked.
  • When you press the home button, or enter a multitasking screen, or somehow switch to another app, the state switches to inactive, stays there for a very short time, and then enters the background state. By default, apps enter the background state for about 10 seconds and then enter the pending state.

Various states of the application:

state Is the interface visible? Whether events can be received Whether the code can be executed
Not running state no no no
active is is is
Inactive state Most of the no is
Background running state no no is
Pending state no no no

model

The standard model-view-controller design pattern requires control objects to be responsible for saving and reading model objects. But that didn’t work out very well. Controlling objects, whose primary task is to handle the interaction between model objects and view objects, can be overwhelming if they are also responsible for implementing all the access details. To do this, move the access logic for model objects into another class of objects: storage objects.

The implementation details of saving and reading model objects are entirely the responsibility of the stored objects. Store Objects Create and save model objects in the following ways:

  • Create and save by specifying a folder.
  • Through the database
  • Through Web services
  • other

The design pattern is Model-View-Controller-Store.

The benefits of this design pattern:

  1. Simplified controller class
  2. You can modify how stored objects work without modifying controller objects or other parts of the application. Therefore, no matter how many control objects the application has to access data, it only needs to modify the corresponding storage objects.

NSException and NSError

NSException and NSError are used in different scenarios.

NSException If you need to point out a programmer’s coding error, you should use NSException. For example, if a method can only accept an odd number as an argument, but the programmer passes an even number when calling the method, an exception should be thrown to make it easier for the programmer to resolve the code error.

NSError NSError should be used for expected errors, such as user errors and device environment errors. For example, if a method needs to read a user’s photo, but does not have access to the user’s album, an NSError object should be returned to the method caller indicating why this operation could not be performed.

Read and write to the document system

Like NSString, NSDictionary and NSArray have writeToFile: and initWithContentsOfFile:. Only when the container object contains property List Serializable objects can data be written using methods such as writeToFile:.

Serializable objects include NSString, NSNumber, NSData, NSArray, and NSDictionary. File writing methods for objects such as NSArray and NSDictionary generate PROPERTY list files in XML format.

Create a UITableViewCell subclass

Block objects should be declared copy

Block objects are declared copy because the system manages their memory differently from other objects, which are created on the stack while other objects are created in the heap. This means that even if the application reserves a strong reference pointer to the newly created block object, the newly created block object will be freed as soon as the method that created it returns. To preserve a block object after the method that declared it returns, you must send it a copy message. When a block object is copied, the application creates a backup of the object in the heap.

The Web service

NSURL NSURLRequest NSURLSessionTask NSURLSession

  • NSURLObject is responsible for saving the location of the Web application in the format of a URL. For most Web services, the URL will contain the base address, the Web application name, and the parameters that need to be passed.
  • NSURLRequestObject is responsible for holding all the data that needs to be passed to the Web server. This data includes: an NSURL object, the caching scheme, the maximum time to wait for a Web server response, and additional information that needs to be sent over HTTP (NSMutableURLRequest is a subclass of NSURLRequest).
  • eachNSURLSessionTaskThey all represent oneNSURLRequestThe life cycle of,NSURLSessionTaskCan trackNSURLRequestCan also be rightNSURLRequestExecute cancel, pause, continue operation.NSURLSessionTaskThere are several subclasses of different functions, includingNSURLSessionDataTask, NSURLSessionUploadTask, NSURLSessionDownloadTask.
  • NSURLSessionAn object can be thought of as a productionNSURLSessionTaskObject factory. Can be set to produceNSURLSessionTaskObject’s generic properties. Such as the content of the request header, whether the request is allowed to be sent over the cellular network, etc.NSURLSessionThere is also a powerful delegate for tracingNSURLSessionTaskObject status, processing server authentication requirements, etc.

The server assigns Web services to different paths based on functionality, and then asks the client to request different Web services with the paths as parameters.

The URL string must be URL-safe. For example, space characters and double quotes are not allowed in urls and must be replaced with escape sequences: NSString *search = @”Play some \”Abba\””; NSString *escaped = [search stirngByAddingPercentEscapsUsingEncoding:NSUTF8StringEncoding]; // Play%20some%20%22Abba%22

Remove escape: stringByRemovingPercentEncoding

Apple provides a class specifically for parsing JSON data: NSJSONSerialization. You can convert objects in JSON data to corresponding OC objects.

By default, NSURLSessionDataTask executes the completionHandler in the background thread. [image upload failed…(image-b5deb4-1509616086734)]

The body of the HTTP request is the data that is sent to the server, usually in XML format, JSON format, or Base-64 encoded data. If a request contains a body, it must include the Content-Length header. NSURLRequest calculates the size of the body and automatically adds the Content-Length header.

Core Data

Solidification mechanism: The biggest disadvantage of using the solidification mechanism is that the data must be stored and retrieved. To access any data in the solidification file, the entire file must be unconsolidated. To save any changes to the data, the entire file must be overwritten.

Core Data: Core Data has no such disadvantages. Core Data can read only a small portion of the existing objects. If the removed object changes, just update the corresponding part. This incremental read, update, delete, and insert feature of Core Data can greatly improve performance if an application is moving a large number of model objects between the file system and RAM.

CoreData stores the Transformable type. When storing or restoring the entity properties of the Transformable type, CoreData first converts them to NSData, and then stores them to the file system or restores them to OC objects. To describe the transformation process to Core Data, you need to create a subclass of NSValueTransformer.

The NS-Managed ObjectContext in the Core Data framework is responsible for the interaction between the application and the database. Through the NSPersistentStoreCoordinator NSManagedObjectContext object use object, you can specify the file path and open the corresponding SQLite database. NSPersistentStoreCoordinator objects need to fit a model file to work (NSManagedObjectModel object can represent the model file).

Enabling State Recovery

If status recovery is enabled for an application, the system traverses each node in the application tree before terminating the application and records the status information of each node, such as the unique identifier of the object, class, and status data to be saved. After the application is terminated, the system stores this information to the file system.

The unique identifier of an object is also called the restoration identifier of the object. Usually the same as the class name of the object; A class is called a Restoration class and is usually the same class to which the object’s ISA pointer points; The state data holds the state information of the object. For example, the state data of UITabBarController includes which label item is currently selected.

After an application is restarted, the system reads the previously saved status information, recreates the application tree, and restores each node in the tree in sequence:

  • The system creates a new view controller for the node through its recovery class.
  • Assign a set of recovery identifiers to a new node: the recovery identifiers for this node and all of its ancestors. The first identifier in the array is the recovery identifier of the root node, and the last identifier is the recovery identifier of the new node.
  • Assign the corresponding state data to the new node. The state data is stored in an NSCoder object.