UIKIt学习笔记—App and Environment部分(一)

这两天面了牛客网,加上期末考试,所以没有更新,成功拿到offer啦!之后会继续每日更新的!
牛客网的面经在这

今天2021年12月24日,各位平安夜快乐
这一部分是

Responding to the Launch of Your App

每个App都有一个关联的进程,即一个UIApplication对象,App还有一个遵守UIApplicationDelegate协议的app代理对象,用来响应在启动过程中的重要事件。在启动时,UIKit自动创建UIApplication对象和app代理,之后启动主事件周期。

重要提示:iOS14之后启动界面被限制在25MB以下,所以不要用净态图像

下面两个方法处理启动时的初始化代码
application(:willFinishLaunchingWithOptions:)
application(
:didFinishLaunchingWithOptions:)

UIKit calls these methods at the beginning of your app’s launch cycle. Use them to:
Initialize your app’s data structures.
Verify that your app has the resources it needs to run.
Perform any one-time setup when your app launches for the first time. For example, install templates or user-modifiable files in a writable directory.
Connect to any critical services that your app uses. For example, connect to the Apple Push Notification service if your app supports remote notifications.
Check the launch options dictionary for information about why your app launched.

UIKit调用他们做以下操作:

初始化app的数据结构
确定app有运行所需的资源
当app第一次启动时执行所有一次的设置,比如往可写字典中写入模版或用户可更改的文件
链接所有用户需要使用的权限或服务,比如app的消息推送
检查可选启动字典

Use the application(_:didFinishLaunchingWithOptions:) method to make additional changes to that interface before it appears onscreen

用application(_:didFinishLaunchingWithOptions:) 方法实现一些额外的操作,比如做一个VC来反应用户上次用app做了什么

When the user launches your app, make a good impression by launching quickly. UIKit doesn’t present your app’s interface until after the application(:didFinishLaunchingWithOptions:) method returns. Performing long-running tasks in that method or your application(:willFinishLaunchingWithOptions:) method might make your app appear sluggish to the user. Returning quickly is also important when launching to the background because the system limits your app’s background execution time
尽量别让application(_:didFinishLaunchingWithOptions:) 方法做一些耗时操作,会堵塞UI,系统还会对后台执行时间做限制。那些不是启动时必要的或者耗时的就放到全局的派发队列里去就行了

When UIKit launches your app, it passes along a launch options dictionary to your application(:willFinishLaunchingWithOptions:) and application(:didFinishLaunchingWithOptions:) methods with information about why your app launched. The keys in that dictionary indicate important tasks to perform immediately. For example, they might reflect actions that the user started elsewhere and wants to continue in your app. Always check the contents of the launch options dictionary for keys that you expect, and respond appropriately to their presence.

Note
For a scene-based app, examine the options that UIKit passes to the application(_:configurationForConnecting:options:) method to determine why it created your scene.

Listing 1 shows the app delegate method for an app that handles background location updates. When the location key is present, the app starts location updates immediately instead of deferring them until later. Starting location updates allows the Core Location framework to deliver the new location event.
Listing 1 Responding to a location event at launch time

class AppDelegate: UIResponder, UIApplicationDelegate, 
               CLLocationManagerDelegate {
    
   let locationManager = CLLocationManager()
   func application(_ application: UIApplication,
              didFinishLaunchingWithOptions launchOptions:
              [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
       
      // If launched because of new location data,
      //  start the visits service right away.
      if let keys = launchOptions?.keys {
         if keys.contains(.location) {
            locationManager.delegate = self
            locationManager.startMonitoringVisits()
         }
      }
       
      return true
   }
   // other methods…
}

The system doesn’t include a key unless your app supports the corresponding feature. For example, the system doesn’t include the remoteNotification key for an app that doesn’t support remote notifications.

UIApplication

When an app launches, the system calls the UIApplicationMain(:::😃 function. Among its other tasks, this function creates a singleton UIApplication object that you access using shared.
App启动时,系统调用UIApplicationMain(:::😃 方法,UIApplication对象是单例,用shared访问

Your app’s application object handles the initial routing of incoming user events. It dispatches action messages forwarded to it by control objects (instances of the UIControl class) to appropriate target objects. The application object maintains a list of open windows (UIWindow objects), which it can use to retrieve any of the app’s UIView objects.
Application对象处理用户事件,通过UIControl类实例派发动作消息给适合的目标对象,application对象包括一个window列表(UIWindow对象),用来获取app的任何UIView对象。

UIApplication类定义一个遵守UIApplicationDelegate协议的代理,application对象通知代理处理一些重要的运行时事件,比如app启动,内存警告等等

App之间可以共用一些资源,比如通过传一个email的URL给open(:options:completionHandler:) 方法可以用邮件app发送或显示邮件
The APIs in this class allow you to manage device-specific behavior. Use your UIApplication object to do the following:
这个类中的接口使你可以管理一些设备相关的行为,用UIApplication对象做以下工作
Temporarily suspend incoming touch events (beginIgnoringInteractionEvents())
Register for remote notifications (registerForRemoteNotifications())
Trigger the undo-redo UI (applicationSupportsShakeToEdit)
Determine whether there is an installed app registered to handle a URL scheme (canOpenURL(
😃)
Extend the execution of the app so that it can finish a task in the background (beginBackgroundTask(expirationHandler:) and beginBackgroundTask(withName:expirationHandler:))
Schedule and cancel local notifications (scheduleLocalNotification(😃 and cancelLocalNotification(😃)
Coordinate the reception of remote-control events (beginReceivingRemoteControlEvents() and endReceivingRemoteControlEvents())
Perform app-level state restoration tasks (methods in the Managing the State Restoration Behavior task group)

Perform any one-time tasks in your app delegate’s application(:willFinishLaunchingWithOptions:) or application(:didFinishLaunchingWithOptions:) method. Never block the app’s main thread for tasks that do not require user input.
在代理的application(:willFinishLaunchingWithOptions:) or application(:didFinishLaunchingWithOptions:) 方法中完成一次性的工作,别让那些不需要用户输入的工作阻塞主线程,让他们去其他线程上异步。

Your app has its own container directory for storing files, and you should always place app-specific files in the ~/Library subdirectory. Specifically, store your files in the following ~/Library subdirectories:
~/Library/Application Support/—Store app-specific files that you want backed up with the user’s other content. (You can create custom subdirectories here as needed.) Use this directory for data files, configuration files, document templates, and so on.
~/Library/Caches/—Store temporary data files that can be easily regenerated or downloaded.
To obtain a URL for one of the directories in your app’s container, use the urls(for:in:) method of FileManager.
Listing 1 Getting the location of app-specific directories

let appSupportURL = FileManager.default.urls(for: 
      .applicationSupportDirectory, in: .userDomainMask)


let cachesURL = FileManager.default.urls(for: 
      .cachesDirectory, in: .userDomainMask)

Place any temporary files in your app’s tmp/ directory. Temporary files might include compressed files that you intend to delete once their contents have been extracted and installed elsewhere. Retrieve the URL for your app’s temporary directory using the temporaryDirectory method of FileManager.

每个app有自己独立的文件目录,~/Library/Application Support/存一些数据,配置。默认文件等等,~/Library/Caches/存一些容易下载的缓存文件
用FileManager的 urls(for:in:) 方法获取路径URL
Tmp/里面存一些临时文件,或解压之后需要被删除的压缩文件。用FileManager的 temporaryDirectory 方法获取临时文件夹的URL
app启动时执行顺序如下在这里插入图片描述

The user or the system launches your app, or the system prewarms your app. For more information about prewarming, see Prepare Your App for Prewarming.
The system executes the main() function that Xcode provides.
The main() function calls UIApplicationMain(:::😃, which creates an instance of UIApplication and of your app delegate.
UIKit loads the default storyboard you specify in your app’s Info.plist file, or in the target’s Custom iOS Target Properties tab of Xcode’s project editor; apps that don’t use a default storyboard skip this step.
UIKit calls the application(:willFinishLaunchingWithOptions:) method in your app delegate.
UIKit performs state restoration, which results in the execution of additional methods in your app delegate and app’s view controllers. For more information, see About the UI Restoration Process.
UIKit calls your app delegate’s application(
:didFinishLaunchingWithOptions:) method.

启动完成后,系统用app代理显示UI,管理生命周期

系统预热您的应用程序后,其启动顺序将处于暂停状态,直到应用程序启动并恢复序列,否则系统将预热应用程序从内存中删除以回收资源。系统可以在设备重新启动后并在系统条件允许的情况下定期预热您的应用程序。

Prewarming an app results in an indeterminate amount of time between when the prewarming phase completes and when the user, or system, fully launches the app. Because of this, use MetricKit to accurately measure user-driven launch and resume times instead of manually signposting various points of the launch sequence.
预热应用程序会导致从预热阶段完成到用户或系统完全启动应用程序之间的时间不确定。因此,使用MetricKit准确测量用户驱动的启动和恢复时间,而不是手动标示启动序列的各个点

About the UI Preservation Process

Figure 1 illustrates the sequence of calls that happens during the interface preservation process. After asking your app delegate if you want your app state to be preserved, UIKit encodes the objects currently in your app’s view controller hierarchy. Only view controllers with a valid restorationIdentifier are preserved.
当你需要暂时保存界面和app状态时,UIKit会做以下操作
只有具有合法的restorationIdentifier 的VC才会被保存

The preservation process walks your view controller hierarchy and recursively encodes the objects that it finds. The process starts with the root view controllers of your app’s windows, which write their data to the provided archive. If the root view controller’s data includes references to other view controllers, UIKit asks each new view controller to encode its data in a separate portion of the archive. Those child view controllers may then encode their own children, and so on.
UIKit view controllers automatically encode their child view controllers, as appropriate. If you define a custom container view controller, your view controller’s encodeRestorableState(with:) method must similarly write any child view controllers to the provided archive.
保存过程会遍历VC层级并且编码所有找到的对象,从window的根VC开始,如果根VC的数据中保存了其他VC的引用,UIKit会要求每个新视图控制器单独对其数据进行编码。然后,这些子VC可以对自己的子视图进行编码,依此类推。如果你自定义了一个容器VCencodeRestorableState(with:) 方法将所有子VC写入提供的文档中

两种方法不保存VC状态,VC如果不保存那么他子视图也不会被保存
在这里插入图片描述

Set its restorationIdentifier property to nil.
Provide a restoration class and return nil from the viewController(withRestorationIdentifierPath:coder:) method.

Any object that adopts the UIStateRestoring protocol can also be included in the restoration archive. For example, you might adopt this protocol in an object that stores global configuration data for your app. To add an object like this to the archive:
Register the object while your app is running by calling the registerObject(forStateRestoration:restorationIdentifier:) method of UIApplication. For example, you might register a configuration object immediately after creating it.
In one of your encodeRestorableState(with:) methods, encode the object into the restoration archive. You can also encode it in your app delegate’s application(_:willEncodeRestorableStateWith:) method.
You can encode any data you want for your custom objects, as long as it is sufficient to return that object to its previous state during the next launch cycle. Encode data that is not crucial to your app’s behavior, and never encode data that should be persisted in other ways. For example, do not encode your app’s settings or user data that must persist between launch cycles.
状态重载没有限制,只要那个对象遵守UIStateRestoring 协议他就可以被保存以便后期重载。对对应用程序的行为不重要的数据进行编码,切勿对应该以其他方式持续的数据进行编码。例如,不要对应用程序的设置或必须在启动周期之间持续存在的用户数据进行编码。

About the UI Restoration Process

Figure 1 illustrates the sequence of calls that happens from the time your app launches until the time it is restored. Restoration occurs during the middle of your app’s initialization, and it proceeds only when a state restoration archive is available and your app delegate’s application(:shouldRestoreApplicationState:) method returns true.
重载发生在app初始化期间,他将会在重载日志可用时或app代理的application(
:shouldRestoreApplicationState:) 方法返回true时进行,下图为重载步骤
Figure 1 The interface restoration sequence
在这里插入图片描述

create the view controller objects (either explicitly or implicitly) for your interface.
decode and restore the state of those objects. Both steps are needed to recreate your view controller hierarchy. For example, after the creation of a navigation controller and its child view controllers, there is no immediate connection between those objects. It is actually the navigation controller’s decodeRestorableState(with:) method that reestablishes the relationships to its child view controllers.
After state restoration finishes, UIKit calls the app delegate’s application(_:didFinishLaunchingWithOptions:) method. Use that method to make any last minute changes or additions to your interface. For example, you might add a login screen to the view controller hierarchy.

Recreate Your View Controllers

During restoration, UIKit tries to create or locate view controller objects from your preserved interface. UIKit first asks you to provide the view controller object. If you do not provide the view controller, UIKit looks for it implicitly. Here is the sequence of steps that UIKit follows to recreate view controllers:
Ask the view controller’s restoration class. A restoration class knows how to create a specific view controller. You designate a restoration class by assigning that class to the restorationClass property of your view controller. During restoration, UIKit calls the viewController(withRestorationIdentifierPath:coder:) method of the restoration class to request a new instance of the view controller, which your method then returns. If you return nil, UIKit stops trying to create the view controller and leaves it out of the restoration process.
Ask the app delegate. If the view controller had no restoration class, UIKit calls the application(_:viewControllerWithRestorationIdentifierPath:coder:) method of the app delegate. If you return nil from that method, UIKit continues searching.
Check for an existing object. UIKit looks for an already created view controller with the exact same restoration path.
Instantiate the view controller from your storyboards. If it still does not have the view controller, UIKit automatically instantiates it from your app’s storyboards.
Before state restoration even begins, UIKit loads your app’s default view controllers from your storyboards. Because UIKit loads these view controllers for free, it is better not to create them using a restoration class or your app delegate. For all other view controllers, assign a restoration class only if the view controller is not defined in your storyboards. You might also assign a restoration class to prevent the creation of your view controller in specific circumstances. For example, you might want to avoid displaying the view controller if the associated restoration archive refers to stale or missing data.
When recreating view controllers in code, always reassign a value to the view controller’s restorationIdentifier property in addition to any other initialization. Also assign a value to the restorationClass property as appropriate. Assigning these values at creation time ensures that the view controller will be preserved during the next cycle.

func viewController(withRestorationIdentifierPath 
                    identifierComponents: [Any], 
                    coder: NSCoder) -> UIViewController? {
   let vc = MyViewController()
        
   vc.restorationIdentifier = identifierComponents.last as? String
   vc.restorationClass = MyViewController.self
        
   return vc
}

Note
Your restoration class should always return the class expected by UIKit. The restoration archive includes the class of each preserved view controller. If your restoration class returns an instance of a different class, UIKit does not call that view controller’s decodeRestorableState(with:) method.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值