美文网首页
NSOperation官方介绍

NSOperation官方介绍

作者: liang1030 | 来源:发表于2021-09-07 16:58 被阅读0次

    一,NSOperation:

    表示与单个任务相关联的代码和数据的抽象类。

    二,Overview:

    因为NSOperation是一个抽象类,你不应该直接使用它,而是应该使用它的子类,或者使用系统定义的子类(NSInvocationOperation或者NSBlockOperation) 来执行真正的任务。尽管是抽象的,NSOperation的基本实现确实包含重要的逻辑来协调任务的安全执行。这种内置逻辑的存在使您能够关注任务的实际实现,而不是确保它与其他系统对象正确工作所需的粘合代码。

    一个operation对象是一个single-shot对象,也就是说,它只执行一次任务,不能用于再次执行。通常通过将操作添加到操作队列(NSOperationQueue类的实例)来执行操作。操作队列通过在辅助线程上运行操作直接执行其操作,或间接使用libdispatch库(也就是Grand Central Dispatch)执行其操作。

    如果您不想使用操作队列,您可以通过直接调用NSOperation的start方法自己执行操作。手动执行操作会给代码带来更多负担,因为启动未处于就绪状态的操作会触发异常。ready属性标记了操作是否就绪。

    三,Operation依赖:

    依赖项是按特定顺序执行操作的便捷方法,你可以通过addDependency:和removeDependency:方法为操作添加或者移除依赖。默认情况下,具有依赖项的操作对象在其所有依赖操作对象完成执行之前,不会被视为就绪。但是,一旦最后一个依赖操作完成,操作对象就准备好并能够执行。

    NSOperation支持的依赖项不区分依赖操作是否成功完成。(换句话说,取消操作同样会将其标记为已完成。) 如果某个具有依赖关系的操作被取消或未成功完成其任务,则由您决定是否应继续执行该操作。这可能需要您将一些额外的错误跟踪功能合并到操作对象中。

    四,KVO-Compliant Properties:

    NSOperation类的一些属性符合键值编码(KVC)和键值观察(KVO)。根据需要,您可以观察这些属性来控制应用程序的其他部分。使用以下键值路径观察这些属性:

    isCancelled--只读
    isAsynchronous--只读
    isExecuting--只读
    isFinished--只读
    isReady--只读
    dependencies--只读
    queuePriority--读写
    completionBlock--读写

    尽管可以添加观察者观察这些属性,但不应使用Cocoa bindings将它们绑定到应用程序用户界面的元素。与用户界面关联的代码通常只能在应用程序的主线程中执行。由于操作可以在任何线程中执行,因此与该操作相关联的KVO通知也可能在任何线程中发生。

    如果您为上述任何属性提供自定义实现,则您的实现必须保持KVC和KVO遵从性。如果您为NSOperation对象定义了其他属性,建议您也使这些属性与KVC和KVO兼容。有关如何支持键值编码的信息,请参见:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i,有关如何支持关键价观察的信息,请参见:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i

    五,多核考虑

    NSOperation类本身具有多核意识。因此,从多个线程调用NSOperation对象的方法是安全的,而无需创建额外的锁来同步对该对象的访问。这种行为是必要的,因为操作通常在与创建并监视它的线程不同的线程中运行。

    当您写NSOperation子类时,必须确保任何被重写的方法都可以安全地从多个线程调用。如果在子类中实现自定义方法,例如自定义数据访问器,则还必须确保这些方法是线程安全的。因此,必须同步对操作中任何数据变量的访问,以防止潜在的数据损坏。有关同步的详细信息,请参见:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html#//apple_ref/doc/uid/10000057i

    六,异步与同步操作

    如果计划手动执行操作对象,而不是将其添加到队列中,则可以将操作设计为以同步或异步方式执行。默认情况下,操作对象是同步的。在同步操作中,操作对象不会创建单独的线程来运行其任务。当您直接用代码调用同步操作的start方法时,该操作将立即在当前线程中执行。当这样一个对象的start方法将控制权返回给调用者时,任务本身就完成了。

    调用异步操作的start方法时,该方法可能会在相应任务完成之前返回。异步操作对象负责在单独的线程上调度其任务。该操作可以通过直接启动新线程、调用异步方法或将block块提交到调度队列执行来实现。实际上,当控件返回给调用方时,操作是否正在进行并不重要,只是它可能正在进行。

    如果您总是计划使用队列来执行操作,那么将它们定义为同步会更简单。但是,如果手动执行操作,则可能希望将操作对象定义为异步。定义异步操作需要更多的工作,因为您必须监视任务的当前状态,并使用KVO通知报告该状态的更改。但是,在需要确保手动执行的操作不会阻塞调用线程的情况下,定义异步操作非常有用。

    将操作添加到操作队列时,队列将忽略asynchronous属性的值,并始终从单独的线程调用start方法。因此,如果总是通过将操作添加到操作队列来运行操作,则没有理由使其异步。

    有关如何定义同步和异步操作的信息,请参subclassing notes。

    七,subclassing notes

    NSOperation类提供了跟踪操作执行状态的基本逻辑,但在其他情况下,必须进行子类化才能执行任何实际工作。创建子类的方式取决于操作设计为并发执行还是非并发执行。

    重写方法

    对于非并发操作,通常只重写一个方法:

    main

    在这个方法中,您放置了执行给定任务所需的代码。当然,您还应该定义一个自定义初始化方法,以便更容易地创建自定义类的实例。您可能还需要定义getter和setter方法来访问操作中的数据。但是,如果您确实定义了自定义getter和setter方法,则必须确保可以从多个线程安全地调用这些方法。

    如果要创建并发操作,则至少需要重写以下方法和属性:

    start
    asynchronous
    executing
    finished

    在并发操作中,start方法负责以异步方式启动操作。无论是生成线程还是调用异步函数,都可以通过此方法完成。在启动操作时,start方法还应该更新由executing属性报告的操作的执行状态。您可以通过发送executing键值路径的KVO通知来实现这一点,这会让感兴趣的客户端知道操作正在运行。executing属性还必须以线程安全的方式提供状态。

    完成或取消其任务后,并发操作对象必须为isExecuting和isFinished键值路径生成KVO通知,以标记操作的最终状态更改。(在取消的情况下,更新isFinished键值路径仍然很重要,即使操作没有完全完成其任务。操作队列必须报告它们已完成,然后才能从队列中删除。)除了生成KVO通知外,对executing和finished属性的重写还应根据操作的状态继续报告准确的值。

    有关如何定义并发操作的更多信息和指导,请看:https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091

    重要的:

    在start方法中,任何时候都不应该调用super。定义并发操作时,您需要自己提供与默认启动方法相同的行为,包括启动任务和生成适当的KVO通知。您的start方法还应该在实际启动任务之前检查操作本身是否已取消。有关取消语义的更多信息,请看Responding to the Cancel Command。

    即使对于并发操作,也不需要重写除上述方法之外的其他方法。但是,如果自定义操作的依赖项功能,则可能必须重写其他方法并提供其他KVO通知。对于依赖项,这可能只需要为isReady键值路径提供通知。因为dependencies属性包含依赖操作的列表,所以对它的更改已经由默认的NSOperation类处理。

    八,维护操作对象状态

    操作对象在内部维护状态信息,以确定何时可以安全执行,并在操作的整个生命周期内通知外部客户端进程。自定义子类维护此状态信息,以确保代码中操作的正确执行。与操作状态关联的键值路径为:

    isReady

    isReady键值路径让客户端知道操作何时准备好执行。ready属性当操作准备好立即执行时值为true,当仍然存在操作依赖的其他操作未完成时值为false。

    在大多数情况下,您不必自己管理此键值路径的状态。如果您的操作准备就绪是由非依赖操作的因素决定的,例如程序中的某些外部条件,则您可以提供自己的就绪属性实现,并自己跟踪操作准备就绪情况。不过,仅在外部状态允许时创建操作对象通常更简单。

    在macOS 10.6及更高版本中,如果你取消了一个操作,而该操作正在等待一个或多个依赖操作的完成,那么这些依赖项将被忽略,该属性的值将被更新,以反映该操作现在已经准备好运行了。此行为使操作队列有机会更快地将被取消的操作从队列中清除出来。

    isExecuting

    isExecuting路径让客户端知道操作是否正在积极处理其分配的任务。如果操作正在执行任务executing值为true,否则为false。如果替换操作对象的start方法,则还必须替换executing属性,并在操作的执行状态更改时生成KVO通知。

    isFinished

    isFinished路径让客户端知道某个操作已成功完成其任务或已取消并正在退出。直到isFinished路径上的值更改为true,操作对象才会清除依赖项。类似地,在finished属性值true之前,操作队列不会将操作出列。因此,将操作标记为已完成对于防止队列备份正在进行或已取消的操作至关重要。

    如果替换start方法或操作对象,还必须替换finished属性,并在操作完成执行或取消时生成KVO通知。

    isCancelled

    isCancelled路径让客户端知道已请求取消操作。对取消的支持是自愿的,但受到鼓励,您自己的代码不必需为此路径发送KVO通知。

    九,响应取消命令

    一旦将操作添加到队列中,操作就不再由您控制了。队列接管并处理该任务的调度。但是,如果您稍后决定不执行该操作(例如,用户按下了进度面板中的取消按钮或退出应用程序),您可以取消该操作,以避免不必要地消耗CPU时间。可以通过调用操作对象本身的cancel方法或调用NSOperationQueue类的cancelAllOperations方法来实现。

    取消一个操作不会立即迫使它停止正在做的事情。尽管所有操作都需要考虑cancelled属性中的值,但代码必须显式检查此属性中的值,并根据需要中止。NSOperation的默认实现包括对取消的检查。例如,如果在调用启动方法之前取消操作,则启动方法将退出,而不会启动任务。

    注意

    在macOS 10.6及更高版本中,如果对操作队列中的操作调用cancel方法,并且该操作具有未完成的依赖操作,则这些依赖操作随后将被忽略。由于该操作已被取消,因此此行为允许队列调用该操作的start方法以从队列中删除该操作,而无需调用其main方法。如果对不在队列中的操作调用cancel方法,则该操作将立即标记为被取消。在每种情况下,将操作标记为ready(就绪)或finished(完成)会生成适当的KVO通知。

    在编写的任何自定义代码中,都应该始终支持取消语义。特别是,主任务代码应该定期检查cancelled属性的值。如果属性的值是YES,您的操作对象应该尽快清理并退出。如果您实现了自定义的start方法,那么该方法应该包括对取消的早期检查,并且行为应该适当。您的自定义start方法必须准备好处理这种类型的提前取消。

    除了简单地在操作被取消时退出外,将被取消的操作移动到适当的最终状态也很重要。具体来说,如果您自己管理finished(已完成)属性和executing(正在执行)属性的值(可能是因为您正在实现一个并发操作),则必须相应地更新这些属性。具体来说,您必须将finished返回的值更改为YES,将executing返回的值更改为NO。即使操作在开始执行之前被取消,也必须进行这些更改。

    十,主题

    **初始化**
    
    //返回一个初始化的NSOperation对象
    init
    
    **执行操作**
    
    //开始执行操作
    start
    
    //执行接收方的非并发任务
    main
    
    //在操作的主要任务完成后要执行的块
    completionblock
    
    **取消操作**
    
    //建议操作对象停止执行其任务
    cancel
    
    **获取操作状态**
    
    //指示操作是否已被取消的布尔值
    cancelled
    
    //指示操作当前是否正在执行的布尔值
    executing
    
    //指示操作是否已完成其任务的布尔值
    finished
    
    //指示操作是否异步执行其任务的布尔值
    concurrent
    
    //指示操作是否异步执行其任务的布尔值
    asynchronous
    
    //指示操作现在是否可以执行的布尔值
    ready
    
    //操作的名称
    name
    
    **依赖关系管理**
    
    //使接收者依赖于指定操作的完成
    addDependency:
    
    //移除接收者对指定操作的依赖关系
    removeDependency:
    
    //一个操作对象数组,在当前对象可以开始执行之前,该数组中的操作对象必须完成执行
    dependencies:
    
    **配置执行优先级**
    
    //将系统资源授予操作的相对重要性
    qualityOfService
    
    //操作队列中操作的执行优先级
    queuePriority
    
    **等待操作对象执行完成**
    
    //阻塞当前线程的执行,直到操作对象完成它的任务
    waitUntilFinished
    
    **常量**
    
    //通过这些常量,您可以对操作的执行顺序进行优先排序
    NSOperationQueuePriority
    
    //用于表示工作的性质和对系统的重要性。当存在资源争用时,使用高质量的服务类比使用低质量的服务类获得更多的资源。
    NSQualityOfService
    
    

    相关文章

      网友评论

          本文标题:NSOperation官方介绍

          本文链接:https://www.haomeiwen.com/subject/uimkwltx.html