Notification和Delegates

本文深入探讨了Objective-C中的通知(Notifications)和代理(Delegates)机制,包括NSNotification类的使用方法、通知的基本构成及作用,以及代理如何在对象间进行交互。通过示例代码展示了如何注册观察者、发送通知以及利用代理处理特定事件。

看这里

Notification

通知(Notifications)提供了一种从任何地方向任何地方广播消息的方法。Objective-C中的NSNotification类就能实现这样的功能。严格地说,它不是语言的一部分,二是Foundation框架的一部分。但是,你在使用Objective-C时,几乎不可能不使用Foundation。NSNotification的实例通过一个NSNotificationCenter进行广播。

通知包含一个name、一个object和一个元数据字典。object和元数据是可选的,name是必需的。object可以通过向通知中心注册来接受某种通知,这些通知通过name、object或者name和object一起来进行过滤匹配。另外,可以传递一个selector,这样当通知匹配时可以调用。

一个示例代码如下:

//从一个对象注册为观察者
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(thingHappened:)
                                             name:MyThingHappened
                                           object:_myObject];

//从另一个对象发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:MyThingHappend
                                                    object:self
                                                  userInfo:nil];
在这个例子中,一个对象将自己注册为观察者,来接收MyThingHappened通知,并且限制接受对象为_myObject来的该通知。然后,另外一个对象提交通知,将自己作为object,没有元数据(userInfo)。这种情况下,如果提交该通知的的对象是来自注册过的对象上下文中的_myObject,那么该通知将触发thingHappened:调用。

Delegates

delegate定义了一个接口,通过该接口,两个对象之间可以进行交互。在Objective-C中,这常常通过使用@protocol语法的形式化协议来实现。在delegate场景中,一个对象是delegate,另一个对象是delegator。delegator会引用它的delegate,这通过delegator调用低音在delegate协议中的某个方法来发送消息实现。一个示例是在用户接口中的按钮,可以有一个delegate处理按钮点击事件通知。



// Copyright 2017 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.components.background_task_scheduler.internal; import android.app.Notification; import android.app.job.JobParameters; import android.app.job.JobService; import android.os.Build; import android.os.SystemClock; import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.ResettersForTesting; import org.chromium.base.ThreadUtils; import org.chromium.build.annotations.NullMarked; import org.chromium.components.background_task_scheduler.BackgroundTask; import org.chromium.components.background_task_scheduler.TaskParameters; import java.util.HashMap; import java.util.Map; /** Delegates calls out to various tasks that need to run in the background. */ @NullMarked public class BackgroundTaskJobService extends JobService { private static final String TAG = "BkgrdTaskJS"; private BackgroundTaskSchedulerJobService.Clock mClock = System::currentTimeMillis; void setClockForTesting(BackgroundTaskSchedulerJobService.Clock clock) { var oldValue = mClock; mClock = clock; ResettersForTesting.register(() -> mClock = oldValue); } private static class TaskFinishedCallbackJobService implements BackgroundTask.TaskFinishedCallback { private final BackgroundTaskJobService mJobService; private final BackgroundTask mBackgroundTask; private final JobParameters mParams; private final long mTaskStartTimeMs; TaskFinishedCallbackJobService( BackgroundTaskJobService jobService, BackgroundTask backgroundTask, JobParameters params) { mJobService = jobService; mBackgroundTask = backgroundTask; mParams = params; // We are using uptimeMillis here to record the exact amount of time needed for the task // to run that excludes the time spent during deep sleep. mTaskStartTimeMs = SystemClock.uptimeMillis(); } @Override public void taskFinished(final boolean needsReschedule) { // Need to remove the current task from the currently running tasks. All other access // happens on the main thread, so do this removal also on the main thread. // To ensure that a new job is not immediately scheduled in between removing the task // from being a current task and before calling jobFinished, leading to us finishing // something with the same ID, call {@link JobService#jobFinished(JobParameters, // boolean} also on the main thread. ThreadUtils.runOnUiThreadBlocking( new Runnable() { @Override public void run() { if (!isCurrentBackgroundTaskForJobId()) { Log.e(TAG, "Tried finishing non-current BackgroundTask."); return; } mJobService.mCurrentTasks.remove(mParams.getJobId()); mJobService.jobFinished(mParams, needsReschedule); BackgroundTaskSchedulerUma.getInstance() .reportTaskFinished( mParams.getJobId(), SystemClock.uptimeMillis() - mTaskStartTimeMs); } }); } @Override public void setNotification(int notificationId, Notification notification) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) return; ThreadUtils.runOnUiThreadBlocking( () -> { if (!isCurrentBackgroundTaskForJobId()) { Log.e( TAG, "Tried attaching notification for non-current BackgroundTask."); return; } mJobService.setNotification( mParams, notificationId, notification, JobService.JOB_END_NOTIFICATION_POLICY_DETACH); BackgroundTaskSchedulerUma.getInstance() .reportNotificationWasSet( mParams.getJobId(), SystemClock.uptimeMillis() - mTaskStartTimeMs); }); } private boolean isCurrentBackgroundTaskForJobId() { return mJobService.mCurrentTasks.get(mParams.getJobId()) == mBackgroundTask; } } private final Map<Integer, BackgroundTask> mCurrentTasks = new HashMap<>(); @Override public boolean onStartJob(JobParameters params) { ThreadUtils.assertOnUiThread(); BackgroundTask backgroundTask = BackgroundTaskSchedulerFactoryInternal.getBackgroundTaskFromTaskId( params.getJobId()); if (backgroundTask == null) { Log.w(TAG, "Failed to start task. Could not instantiate BackgroundTask class."); // Cancel task if the BackgroundTask class is not found anymore. We assume this means // that the task has been deprecated. BackgroundTaskSchedulerFactoryInternal.getScheduler() .cancel(ContextUtils.getApplicationContext(), params.getJobId()); return false; } if (BackgroundTaskSchedulerJobService.didTaskExpire(params, mClock.currentTimeMillis())) { BackgroundTaskSchedulerUma.getInstance().reportTaskExpired(params.getJobId()); return false; } mCurrentTasks.put(params.getJobId(), backgroundTask); TaskParameters taskParams = BackgroundTaskSchedulerJobService.getTaskParametersFromJobParameters(params); BackgroundTaskSchedulerUma.getInstance().reportTaskStarted(taskParams.getTaskId()); boolean taskNeedsBackgroundProcessing = backgroundTask.onStartTask( ContextUtils.getApplicationContext(), taskParams, new TaskFinishedCallbackJobService(this, backgroundTask, params)); if (!taskNeedsBackgroundProcessing) mCurrentTasks.remove(params.getJobId()); return taskNeedsBackgroundProcessing; } @Override public boolean onStopJob(JobParameters params) { ThreadUtils.assertOnUiThread(); if (!mCurrentTasks.containsKey(params.getJobId())) { Log.w( TAG, "Failed to stop job, because job with job id " + params.getJobId() + " does not exist."); return false; } BackgroundTask backgroundTask = mCurrentTasks.get(params.getJobId()); TaskParameters taskParams = BackgroundTaskSchedulerJobService.getTaskParametersFromJobParameters(params); BackgroundTaskSchedulerUma.getInstance().reportTaskStopped(taskParams.getTaskId()); boolean taskNeedsReschedule = backgroundTask.onStopTask(ContextUtils.getApplicationContext(), taskParams); mCurrentTasks.remove(params.getJobId()); return taskNeedsReschedule; } }
09-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值