2017-07-14 15:45:05 Cloudox_ 阅读数 8634
  • iOS移动开发从入门到精通(Xcode11 & Swift5)

    【课程特点】 学习iOS开发,请选本套课程,理由如下: 1、180节大容量课程:包含了iOS开发中的大部分实用技能; 2、创新的教学模式:手把手教您iOS开发技术,一看就懂,一学就会; 3、贴心的操作提示:让您的眼睛始终处于操作的焦点位置,不用再满屏找光标; 4、语言简洁精练:瞄准问题的核心所在,减少对思维的干扰,并节省您宝贵的时间; 【课程内容】 本视频教程拥有180节课程,包含iOS开发的方方面面:iOS开发基础理论知识、 视图、视图控制器、多媒体、数据处理、常用插件、信用卡卡号识别、自动化测试、网络访问、多线程、ShareSDK社会化分享、CoreImage、CoreText、CoreML机器学习、ARKit增强现实、面部检测、Storyboard技巧、关键帧动画、本地通知、陀螺仪相机定位设备、本地化、通过IAP内购实现营利、App上传与审核等超多干货! 

    2604 人正在学习 去看看 李发展

通知大家都不陌生,其实通知分两种,远程通知和本地通知。

远程通知是指服务器发出的通知,通过苹果的推送然后到达用户设备。本地通知是指不通过网络,直接安装应用后就可以接到通知了,典型的例子是日历、待办、闹钟等应用。

不过就表现形式来说两者基本一样,都会出现在通知中心,都可以出现在锁屏界面,都可以出现在界面上部,都可以添加应用上的红点。

这里我定时不断发送通知,每次收到通知都添加到列表中,点击列表可以复制通知内容。

对于本地通知,iOS 10以前和以后分两种实现方式,这里都放出来。

需要注意的是,现在在Xcode中使用远程通知功能需要在工程的Targets中的Capabilities标签里打开Push Notification权限,且需要APNS证书,不过本地通知是不需要的,可以直接测试接收通知。

iOS 10以上系统的实现

iOS 10以前使用UILocalNotification,iOS开始支持一个新的类库UNUserNotificationCenter,都给了他特定的前缀UN了,可见重视程度。

如上面第一张图所示,要发通知是需要用户同意的,也就是在第一次打开App的时候必须尝试注册通知,如果不注册,那么即使用户去设置中找也无法再通知里找到你的App然后打开。

所以我们需要在AppDelegate.m的application: didFinishLaunchingWithOptions:方法中注册通知:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // 注册通知
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {

        }];


    return YES;
}

这样就会在第一次启动App时向用户索取权限。接下来就可以决定发什么通知以及收到通知后怎么处理了。

我们可以定义一个方法来发通知:

#import <UserNotifications/UserNotifications.h>

……

/**
 iOS 10以后的本地通知
 */
- (void)addlocalNotificationForNewVersion {
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    center.delegate = self;
    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
    content.title = [NSString localizedUserNotificationStringForKey:@"Hello" arguments:nil];
    content.body = [NSString localizedUserNotificationStringForKey:[NSString stringWithFormat:@"Agent-%d",arc4random()%100] arguments:nil];
    content.sound = [UNNotificationSound defaultSound];

    //    UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:alertTime repeats:NO];
    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"OXNotification" content:content trigger:nil];

    [center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
        NSLog(@"成功添加推送");
    }];
}

发通知的所有内容就在这里了,明显可见content是一个通知体,定义通知的一些内容、声音等,然后放到request中,添加到通知中心就可以了。中间注释了一行是用来重复通知的,第一个参数是重复的时间间隔,最小60s,第二个参数是是否重复。因为60s太长了不便于测试,所以不如在外部写一个定时器,重复调用这个方法就可以了。

要接收通知并处理必须要遵循 UNUserNotificationCenterDelegate 这个协议,上面代码中就设置了delegate是self,然后就可以处理接收通知:

#pragma mark - UNUserNotificationCenterDelegate
// iOS 10收到通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {

    NSDictionary * userInfo = notification.request.content.userInfo;
    UNNotificationRequest *request = notification.request; // 收到推送的请求
    UNNotificationContent *content = request.content; // 收到推送的消息内容
    NSNumber *badge = content.badge;  // 推送消息的角标
    NSString *body = content.body;    // 推送消息体
    UNNotificationSound *sound = content.sound;  // 推送消息的声音
    NSString *subtitle = content.subtitle;  // 推送消息的副标题
    NSString *title = content.title;  // 推送消息的标题

    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        NSLog(@"iOS10 前台收到远程通知:%@", body);

    } else {
        // 判断为本地通知
        NSLog(@"iOS10 前台收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
        [self.dataArray addObject:content];
        [self.timeArray addObject:[self convertNSDateToNSString:[NSDate date]]];
        [self.tableView reloadData];
    }
    completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以设置
}

我这边的处理是添加到数组中,并且记录通知的时间,好在列表中显示,至于列表怎么显示就不写在这了,需要的同学可以直接看工程代码。

关于iOS 10的通知流程就是这些了。

iOS 10以前系统的实现

老系统的实现其实要素都差不多,只不过提供的类库不一样,一样需要在应用一开始的时候注册通知:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // 注册通知,如果已经获得发送通知的授权则创建本地通知,否则请求授权(注意:如果不请求授权在设置中是没有对应的通知设置项的,也就是说如果从来没有发送过请求,即使通过设置也打不开消息允许设置)
    if ([[UIApplication sharedApplication] currentUserNotificationSettings].types != UIUserNotificationTypeNone) {
        [self addLocalNotificationForOldVersion];
    } else {
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound  categories:nil]];
    }


    return YES;
}

添加通知我们也放到一个方法中:

/**
 iOS 10以前版本添加本地通知
 */
- (void)addLocalNotificationForOldVersion {

    //定义本地通知对象
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    //设置调用时间
    notification.timeZone = [NSTimeZone localTimeZone];
    notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:2.0];//通知触发的时间,10s以后
    notification.repeatInterval = 2;//通知重复次数
    notification.repeatCalendar=[NSCalendar currentCalendar];//当前日历,使用前最好设置时区等信息以便能够自动同步时间

    //设置通知属性
    notification.alertBody = [NSString stringWithFormat:@"Agent-%d",arc4random()%100]; //通知主体
    notification.applicationIconBadgeNumber += 1;//应用程序图标右上角显示的消息数
    notification.alertAction = @"打开应用"; //待机界面的滑动动作提示
    notification.alertLaunchImage = @"Default";//通过点击通知打开应用时的启动图片,这里使用程序启动图片
    notification.soundName = UILocalNotificationDefaultSoundName;//收到通知时播放的声音,默认消息声音
//    notification.soundName=@"msg.caf";//通知声音(需要真机才能听到声音)

    //设置用户信息
    notification.userInfo = @{@"id": @1, @"user": @"cloudox"};//绑定到通知上的其他附加信息

    //调用通知
    [[UIApplication sharedApplication] scheduleLocalNotification:notification];
}

可以看到能够设置的东西还是蛮多的。

此外还有几个可能用得到的代理方法:

/**
 应用注册通知后

 @param application 应用
 @param notificationSettings 通知设置
 */
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    if (notificationSettings.types != UIUserNotificationTypeNone) {
        [self addLocalNotificationForOldVersion];
    }
}

/**
 应用进入前台时调用

 @param application 应用
 */
- (void)applicationWillEnterForeground:(UIApplication *)application {
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];//进入前台取消应用消息图标
}

/**
 收到通知后回调

 @param application 应用
 @param notification 通知
 */
- (void)application:(UIApplication *)application didReceiveLocalNotification:(nonnull UILocalNotification *)notification {
    NSLog(@"%@", notification.alertBody);
}

不过我用这个老方法在iOS 10的手机上测试收不到通知,不知道是不是在新系统必须要用新的库。

没什么好结的,以上。


示例工程:https://github.com/Cloudox/OXNotificationTest
版权所有:http://blog.csdn.net/cloudox_

2018-11-06 16:23:49 lqq200912408 阅读数 599
  • iOS移动开发从入门到精通(Xcode11 & Swift5)

    【课程特点】 学习iOS开发,请选本套课程,理由如下: 1、180节大容量课程:包含了iOS开发中的大部分实用技能; 2、创新的教学模式:手把手教您iOS开发技术,一看就懂,一学就会; 3、贴心的操作提示:让您的眼睛始终处于操作的焦点位置,不用再满屏找光标; 4、语言简洁精练:瞄准问题的核心所在,减少对思维的干扰,并节省您宝贵的时间; 【课程内容】 本视频教程拥有180节课程,包含iOS开发的方方面面:iOS开发基础理论知识、 视图、视图控制器、多媒体、数据处理、常用插件、信用卡卡号识别、自动化测试、网络访问、多线程、ShareSDK社会化分享、CoreImage、CoreText、CoreML机器学习、ARKit增强现实、面部检测、Storyboard技巧、关键帧动画、本地通知、陀螺仪相机定位设备、本地化、通过IAP内购实现营利、App上传与审核等超多干货! 

    2604 人正在学习 去看看 李发展

通知相关系列文章
iOS10 之前通知使用介绍
[iOS] 通知详解: UIUserNotification
iOS10 相关API
[iOS] 通知详解:iOS 10 UserNotifications API
iOS10 本地/远程通知
[iOS] 通知详解: iOS 10 UserNotifications
iOS10 通知附加包
[iOS] 通知详解: iOS 10 UserNotifications – 附加包Media Attachments
iOS10 自定义UI
[iOS] 通知详解: iOS 10 UserNotifications – 自定义通知UI

新建 Notification content extension

通知UI的自定义使用到了Notification content extension,同创建Notification Service Extension一样,我们需要创建一个新的 Target ,只不过这次选择Notification content extension

下一步,为这个Target起一个名字,完成即可!

可以看到多了下面几个文件:

这里的NotificationViewController就是我们编写自定义UI逻辑的控制器,他和一般的控制器一样,MainInterface.storyboard是与其绑定的,可以在此往storyboard添加控件。Info.plist为其相关的配置文件,有些操作需要在这里配置一些设置后,才能看到预期的效果,下面关于此部分的所有配置,都是在这里进行的。

NotificationViewController中,实现了UNNotificationContentExtension协议,他有两个协议方法

// 必须实现,用来处理自定义UI的内容
public func didReceive(_ notification: UNNotification)
// 选择实现,用来处理action的事件
optional public func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void)

第一个是必须要实现的,在NotificationViewController默认已经实现了,主要是处理当通知来的时候,布局自定义的UI内容以及相关的处理逻辑的地方;
第二个方法,当前发送的通知带有快捷操作action的时候(UNNotificationAction),来处理相关的点击事件。

因为我们自定义的任何View都是无法交互的,只能借助添加的action来处理相关的事件。

绑定 Category

Notification content extension添加完成后,在通知界面是看不到我们自定义的UI的,还需要绑定相关的 Category,即在创建通知的时候,我们添加的UNNotificationCategory,如果没有需要交互的action,可以传个空数组:

let category = UNNotificationCategory(identifier: "categoryidentifier", actions: [], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
        UNUserNotificationCenter.current().setNotificationCategories(Set.init([category]))

然后在该扩展下的Info.plist中添加该Categoryidentifier,对应着UNNotificationExtensionCategory字段:

注意:这里的UNNotificationExtensionCategory可以修改为数组类型,如果我们有多个Category公用一套UI,可以将此值修改为Array类型,然后在数组里添加多个 Category 的identifier。

再去发送通知,注意此时的Payload中要添加category字段:

{
"aps":
    {
        "alert":
        {
            "title":"iOS10远程推送标题",
            "subtitle" : "iOS10 远程推送副标题",
            "body":"这是在iOS10以上版本的推送内容,并且携带来一个图片附件"
        },

"category":"categoryidentifier",
        "badge":1,
        "mutable-content":1,
        "sound":"default",
"image":"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3078873712,1340878922&fm=26&gp=0.jpg"
        
    }
}

弹框和锁屏页显示的内容和之前一样,打开通知或者下拉弹框,就会看到我们自定义的页面了:

比较丑的那部分就是我们自定义的UI了,可以看到真的很丑,大小还不合适,而且和系统默认的也重复的。

如果我们想要隐藏系统默认的内容页面,也就是下面的那部分,头是隐藏不了的;只需要在Info.plist里添加字段UNNotificationExtensionDefaultContentHidden,bool类型并设置其值为YES;

关于页面太大的问题,有的说通过修改其宽高比UNNotificationExtensionInitialContentSizeRatio的值,如果你的UI是固定的,可以通过适配大部分屏幕后,通过修改此值来得到合适的宽高比视图,但其值也是需要各种尝试的。
另外也可以使用autolayout,如果是在storyboard里添加的实图,顺便添加相应的约束即可;然后重新发送消息,大概就是这个样子:

这样,通知页面会先显示一个大的页面,然后再resize到约束后的页面大小,这样就会一个缩放的动画,这是因为在通知即将展示的时候,系统还没有调用我们的约束代码,也就是约束还没有起效,所以会有个resize的动画过渡。
为解决这个问题,只能在自定义UI的时候配合UNNotificationExtensionInitialContentSizeRatio设置合适页面大小,即采用固定的样式来展示通知内容。

显示附加包(attachment)的内容

如果我们的通知是携带附加包的,例如一张图片,添加自定义的UI后,打开通知或者下拉弹框会发现,大图不显示了,我们可以把相关的内容显示到自定义的UI上,还是以图片为例,在didReceive方法里添加以下获取附加包数据的代码:

if let att = notification.request.content.attachments.first {

            if att.url.startAccessingSecurityScopedResource() {
                self.coverImage.image  = UIImage(contentsOfFile: att.url.path)
                att.url.stopAccessingSecurityScopedResource()
            }
        }

这里需要说一下startAccessingSecurityScopedResourcestopAccessingSecurityScopedResource方法:
因为attachment是由系统单独管理的,所以这里我们在使用attachment之前,需要告诉iOS系统,我们需要使用它,并且在使用完毕之后告诉系统我们使用完毕了。对应上述代码就是startAccessingSecurityScopedResource()和stopAccessingSecurityScopedResource()的操作。当我们获取到了attachment的使用权之后,我们就可以使用那个文件获取我们想要的信息了。

再去发送上面的Payload,打开后就是这样了:

意思是那么个意思,但是加载的图片好像不太完整,上面我们是从attachment里面获取的,目前不清楚出现这个情况的原因,可能原数据被压缩了导致数据不全。所以,我们可以从发送的Payload中来获取数据:

if let aps = notification.request.content.userInfo["aps"] as? [String: Any] {

            if let imagePath = aps["image"] as? String {

                if let url = URL(string: imagePath) {

                    if let data = try? Data.init(contentsOf: url) {

                        self.coverImage.image = UIImage(data: data)
                    }
                }
            }
        }

这样就能正常显示了:

处理action事件

如果我们添加的category是带有action的,并且action的点击事件要响应到我们自定义的UI里面,例如点击的时候更换一个图片, 就需要UNNotificationContentExtension协议的另一个协议方法了:

// response:可以拿到点击的action,和通知的内容
// completion:处理完成后需要告诉系统,接下来该如何处理该通知
optional public func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void)

UNNotificationContentExtensionResponseOption 是一个枚举,他有三个值:

@available(iOS 10.0, *)
public enum UNNotificationContentExtensionResponseOption : UInt {

    // 通知页面不会消失,例如更新UI,显示出来
    case doNotDismiss
// 关闭当前通知页面
    case dismiss
// 将此action事件传递给app,在通知中心的代理方法里继续处理该事件
    case dismissAndForwardAction
}

需要注意的是,如果实现了此方法,就需要对所有添加的action进行处理,而不能只处理某个action

例如我们这样处理点击事件:

func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) {
// 改变标题
        self.label?.text = self.label?.text ?? "" + "点击了 "
        
        if response.actionIdentifier == "okidentifier" {
            // 点击了查看按钮,这里改变了标题的颜色

            self.label?.textColor = UIColor.red
            
            completion(.doNotDismiss)
        } else if response.actionIdentifier == "cancelidentifier" {
            // 点击了关闭,直接关闭通知
            completion(.dismiss)
        } else {
            // 如果还有其他的按钮,交给app处理
            completion(.dismissAndForwardAction)
        }
    }

然后,在创建通知的时候,添加相应的action:

let okAction = UNNotificationAction(identifier: "okidentifier", title: "查看", options: UNNotificationActionOptions.foreground)
   
        let cancel = UNNotificationAction(identifier: "cancelidentifier", title: "关闭", options: UNNotificationActionOptions.destructive)
        
        let category = UNNotificationCategory(identifier: "categoryidentifier", actions: [okAction, cancel], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
        UNUserNotificationCenter.current().setNotificationCategories(Set.init([category]))

再次发生Payload,点击通知的查看action,会发现标题和标题的颜色都修改了。

处理快捷回复(输入文字)

前面知道,我们可以在通知中心进行快捷回复,只需要创建UNTextInputNotificationAction的action,添加到对应的category即可:

let okAction = UNTextInputNotificationAction(identifier: "okidentifier", title: "回复", options: .foreground, textInputButtonTitle: "快捷回复", textInputPlaceholder: "请输入。。。")
        
        
        let cancel = UNNotificationAction(identifier: "cancelidentifier", title: "关闭", options: UNNotificationActionOptions.destructive)
        
        let category = UNNotificationCategory(identifier: "categoryidentifier", actions: [okAction, cancel], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
        UNUserNotificationCenter.current().setNotificationCategories(Set.init([category]))

这里,我们需要这样来处理接收到的反馈:

func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) {
        self.label?.text = "点击了 "
        
        if response.actionIdentifier == "okidentifier" {
            

            // 这里处理输入框的事件
            if let txRes = response as? UNTextInputNotificationResponse {
                // 如果是输入框的反馈,获取输入内容,显示出来
                let text = txRes.userText
                self.label?.text = text
            }
            
            // 点击了查看按钮,这里改变了标题的颜色
            self.label?.textColor = UIColor.red
            
            completion(.doNotDismiss)
        } else if response.actionIdentifier == "cancelidentifier" {
            // 点击了关闭,直接关闭通知
            completion(.dismiss)
        } else {
            // 如果还有其他的按钮,交给app处理
            completion(.dismissAndForwardAction)
        }
    }

然后在通知中心点击回复按钮的时候会弹出输入框,输入结束后,通知中心即显示了输入的内容:

到此,断断续续,总算是把通知相关的内容整体过了一遍,虽然感觉上还是有些逻辑混乱,基本上能够体现通知的一些使用方法。

参考文章
iOS10-UserNotifications
WWDC2016 Session笔记 - iOS 10 推送Notification新特性

2019-03-13 17:21:49 qq_41856760 阅读数 580
  • iOS移动开发从入门到精通(Xcode11 & Swift5)

    【课程特点】 学习iOS开发,请选本套课程,理由如下: 1、180节大容量课程:包含了iOS开发中的大部分实用技能; 2、创新的教学模式:手把手教您iOS开发技术,一看就懂,一学就会; 3、贴心的操作提示:让您的眼睛始终处于操作的焦点位置,不用再满屏找光标; 4、语言简洁精练:瞄准问题的核心所在,减少对思维的干扰,并节省您宝贵的时间; 【课程内容】 本视频教程拥有180节课程,包含iOS开发的方方面面:iOS开发基础理论知识、 视图、视图控制器、多媒体、数据处理、常用插件、信用卡卡号识别、自动化测试、网络访问、多线程、ShareSDK社会化分享、CoreImage、CoreText、CoreML机器学习、ARKit增强现实、面部检测、Storyboard技巧、关键帧动画、本地通知、陀螺仪相机定位设备、本地化、通过IAP内购实现营利、App上传与审核等超多干货! 

    2604 人正在学习 去看看 李发展

一、通知

通知是iOS中的一种消息传递方式,通过消息中心(NSNotificationCenter)对消息的监听,当某些类发送出消息的时候,消息中心监听到这些消息,然后进行相应的操作,这些操作对于发送出这些消息的类来说是相同的。

下面通过一个demo来说明通知的实现

                                 

就是点击按钮,弹出弹窗,然后点击弹窗中的按钮打印出一些信息。 这个信息是由前面自定义的alertView发出给到控制器的,我们用通知来实现这之间的数据传递。


//viewController.m
- (IBAction)buttonDidClicked:(UIButton *)sender {
    
    LSRAlertView * view = [LSRAlertView alertWithTitle:@"操作完成" andTitleImageName:@"gou"];
    [view addTopButtonWithTitle:@"确定"];
    [view addBottomButtomWithTitle:@"取消"];
    [view show];
    //这里向消息中心注册消息
    //obsever:观察者,谁来监听这个消息
    //selector:监听到发出的对应的消息后要做什么
    //name:监听的消息的名称
    //obeject:保存在消息中心的数据,一般传一个nil
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sureButtonDidClicked) name:@"SureButtonClickedNotificationName" object:nil];
    //取消按钮我们需要传递一些参数
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(cancelButtonClicked:) name:@"CancelButtonClickedNotificationName" object:nil];
    
}

首先在控制器中添加一个按钮点击事件,然后设置弹窗视图(至于如何自定义弹窗视图,请查看我的上一篇文章),接着我们在这里向消息中心注册消息,为什么在这里注册呢?因为我们是要在控制器中获取到弹窗视图的数据,在控制器中注册相应的消息后,控制器就会监听发出我们注册消息的对象,然后执行相应的方法,所以在控制器中注册消息。

接着我们在自定义弹窗视图的类写发送消息的代码,那么又该在哪里写呢?应该在弹窗视图上的按钮被点击了之后写,所以:


//LSRAlertView.m
- (IBAction)topButonClicked:(UIButton *)sender {
     [self dismiss];
    //这里按钮被点击了,此时需要发出消息
    //name:消息的名称,必须和所监听的消息的名称相同
    //object:需要回调的数据
    //userInfo:也是需要回调的数据
    [[NSNotificationCenter defaultCenter]postNotificationName:@"SureButtonClickedNotificationName" object:nil userInfo:nil];
   
}
- (IBAction)bottomButtonClicked:(UIButton *)sender {
    //发出消息的时候回调参数
    [self dismiss];
    [[NSNotificationCenter defaultCenter]postNotificationName:@"CancelButtonClickedNotificationName" object:@"object" userInfo:@{@"name":@"jack"}];
    
}

发送消息我们用postNotificationName,这里需要注意的是发送消息的名称一定要和之前在控制器中注册的消息名对应起来,另外如果我们需要传递一些数据,就将传递的数据写在 object 或者  userInfo 中,前者是一个字符串类型,后者是一个字典类型。

然后是我们在控制器监听到弹窗视图发出的消息后执行的操作:

//ViewController.m
-(void)sureButtonDidClicked{
    //这里不需要回调参数
    NSLog(@"确定按钮被点击了");
    
    //在这里移除消息
    [[NSNotificationCenter defaultCenter]removeObserver:self name:@"SureButtonClickedNotificationName" object:nil];
} 
-(void)cancelButtonClicked:(NSNotification *)notification{
    //这里将传递过来的参数打印出来
    NSLog(@"%@",notification.object);
    NSLog(@"%@",notification.userInfo);
    
    //同样在这里移除消息
    [[NSNotificationCenter defaultCenter]removeObserver:self name:@"CancelButtonClickedNotificationName" object:nil];
    
}

这里需要注意两点,一是如何取出消息中的数据,我们使用notification的属性object和userInfo来取得相应的数据。第二点也是非常重要的就是一定要将消息中的消息移除,一定要将消息中的消息移除,一定要将消息中的消息移除。如果不移除就会导致点击一次按钮触发多次事件,因为有多个相同的消息同时注册了。

最后是打印的信息:

2016-01-12 10:52:27 u012121216 阅读数 280
  • iOS移动开发从入门到精通(Xcode11 & Swift5)

    【课程特点】 学习iOS开发,请选本套课程,理由如下: 1、180节大容量课程:包含了iOS开发中的大部分实用技能; 2、创新的教学模式:手把手教您iOS开发技术,一看就懂,一学就会; 3、贴心的操作提示:让您的眼睛始终处于操作的焦点位置,不用再满屏找光标; 4、语言简洁精练:瞄准问题的核心所在,减少对思维的干扰,并节省您宝贵的时间; 【课程内容】 本视频教程拥有180节课程,包含iOS开发的方方面面:iOS开发基础理论知识、 视图、视图控制器、多媒体、数据处理、常用插件、信用卡卡号识别、自动化测试、网络访问、多线程、ShareSDK社会化分享、CoreImage、CoreText、CoreML机器学习、ARKit增强现实、面部检测、Storyboard技巧、关键帧动画、本地通知、陀螺仪相机定位设备、本地化、通过IAP内购实现营利、App上传与审核等超多干货! 

    2604 人正在学习 去看看 李发展

<span style="font-family: 'Lucida Grande', 'Lucida sans Unicode', Arial, Verdana, sans-serif; background-color: rgb(255, 255, 255);">如果在一个类中想要执行另一个类中的方法可以使用通知</span>
1.创建一个通知对象:使用notificationWithName:object: 或者 notificationWithName:object:userInfo:

    NSNotification* notification = [NSNotification notificationWithName:kImageNotificationLoadFailed(connection.imageURL)
                                                                 object:self
                                                               userInfo:[NSDictionary dictionaryWithObjectsAndKeys:error,@"error",connection.imageURL,@"imageURL",nil]];

这 里需要注意的是,创建自己的通知并不是必须的。而是在创建自己的通知之前,采用NSNotificationCenter类的方 法 postNotificationName:object: 和 postNotificationName:object:userInfo:更加便利的发出通知。这种情况,一般使用NSNotificationCenter的类方法defaultCenter就获得默认的通知对象,这样你就可以给该程序的默认通知中心发送通知了。注意:每一个程序都有一个自己的通知中心,即NSNotificationCenter对象。该对象采用单例设计模式,采用defaultCenter方法就可以获得唯一的NSNotificationCenter对象。

注意:NSNotification对象是不可变的,因为一旦创建,对象是不能更改的。

2.注册通知:addObserver:selector:name:object:

可以看到除了添加观察者之外,还有其接收到通知之后的执行方法入口,即selector的实参。因此为了进行防御式编程,最好先检查观察者是否定义了该方法。例如:添加观察者代码有

[[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(aWindowBecameMain:)
    name:NSWindowDidBecomeMainNotification object:nil];

这里保证了self定义了aWindowBecameMain:方法。而对于一个任意的观察者observer,不能保证其对应的selector有aWindowBecameMain:,可采用[observer respondsToSelector:@selector(aWindowBecameMain:)]] 进行检查。所以完整的添加观察者过程为:

if([observer respondsToSelector:@selector(aWindowBecameMain:)]) {
        [[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(aWindowBecameMain:) name:NSWindowDidBecomeMainNotificationobject:nil];
    }

注 意到addObserver:selector:name:object:不仅指定一个观察者,指定通知中心发送给观察者的消息,还有接收通知的名字,以 及指定的对象。一般来说不需要指定name和object,但如果仅仅指定了一个object,观察者将收到该对象的所有通知。例如将上面的代码中 name改为nil,那么观察者将接收到object对象的所有消息,但是确定不了接收这些消息的顺序。如果指指定一个通知名称,观察者将收到它每次发出 的通知。例如,上面的代码中object为nil,那么客户对象(self)将收到任何对象发出NSWindowDidBecomeMainNotification通知。如果既没有指定指定object,也没有指定name,那么该观察者将收到所有对象的所有消息。

3.发送通知:postNotificationName:object:或者performSelectorOnMainThread:withObject:waitUntilDone:

例如程序可以实现将一个文本可以进行一系列的转换,例如对于一个实例、RTF格式转换成ASCII格式。而转换在一个类(如Converter类)的对象中得到处理,在诚寻执行过程中可以加入或者删除这种转换。而且当添加或者删除Converter操作时,你的程序可能需要通知其他的对象,但是这些Converter对象并不需要知道被通知对象是什么,能干什么。你只需要声明两个通知,"ConverterAdded" 和 "ConverterRemoved",并且在某一事件发生时就发出这两个通知。

当一个用户安装或者删除一个Converter,它将发送下面的消息给通知中心:

[[NSNotificationCenter defaultCenter]
    postNotificationName:@"ConverterAdded" object:self];

或者是

[[NSNotificationCenter defaultCenter]
    postNotificationName:@"ConverterRemoved" object:self];

通知中心将会区分它们对象对这些通知感兴趣并且通知他们。如果除了关心观察者的通知名称和观察的对象,还关心其他之外的对象,那么就把之外的对象放在通知的可选字典中,或者用方法postNotificationName:object:userInfo:。

而采用performSelectorOnMainThread:withObject:waitUntilDone:则是直接调用NSNotification的方法postNotification,而postNotificationName和object参数可以放到withObject的实参中。例如:

[[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES];//注意这里的notification为自定义的一个通知对象,可定义为NSNotification* notification = [NSNotification notificationWithName:@"ConverterAdded"object:self];//那么它的作用与上面的一致

4.移除通知:removeObserver:和removeObserver:name:object:

其中,removeObserver:是删除通知中心保存的调度表一个观察者的所有入口,而removeObserver:name:object:是删除匹配了通知中心保存的调度表中观察者的一个入口。

这个比较简单,直接调用该方法就行。例如:

[[NSNotificationCenter defaultCenter] removeObserver:observer name:nil object:self];

注意参数notificationObserver为要删除的观察者,一定不能置为nil。

Demo:

第一步:注册通知

- (IBAction)backButtonOnClick:(id)sender
{
    //改变完成之后发送通知,告诉其他页面修改完成,提示刷新界面
    [[NSNotificationCenter defaultCenter] postNotificationName:@"sendValue" object:nil];
    
    [self.navigationController popToRootViewControllerAnimated:YES];
}


第二步:在另一个控制器中接收通知

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.title = @"首页";
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeValue:) name:@"sendValue" object:nil];
}

实现方法

- (void)changeValue:(NSNotification *)dictInfo
{
    NSLog(@"接收到了通知");
}


第三步:移除通知


- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Demo下载:





2015-02-27 23:15:58 guoyule2010 阅读数 625
  • iOS移动开发从入门到精通(Xcode11 & Swift5)

    【课程特点】 学习iOS开发,请选本套课程,理由如下: 1、180节大容量课程:包含了iOS开发中的大部分实用技能; 2、创新的教学模式:手把手教您iOS开发技术,一看就懂,一学就会; 3、贴心的操作提示:让您的眼睛始终处于操作的焦点位置,不用再满屏找光标; 4、语言简洁精练:瞄准问题的核心所在,减少对思维的干扰,并节省您宝贵的时间; 【课程内容】 本视频教程拥有180节课程,包含iOS开发的方方面面:iOS开发基础理论知识、 视图、视图控制器、多媒体、数据处理、常用插件、信用卡卡号识别、自动化测试、网络访问、多线程、ShareSDK社会化分享、CoreImage、CoreText、CoreML机器学习、ARKit增强现实、面部检测、Storyboard技巧、关键帧动画、本地通知、陀螺仪相机定位设备、本地化、通过IAP内购实现营利、App上传与审核等超多干货! 

    2604 人正在学习 去看看 李发展
 一个完整的通知一般包含3个属性:

- (NSString *)name; // 通知的名称

- (id)object; // 通知发布者(是谁要发布通知)

- (NSDictionary *)userInfo; // 一些额外的信息(通知发布者传递给通知接收者的信息内容)


初始化一个通知(NSNotification)对象

+ (instancetype)notificationWithName:(NSString *)aName object:(id)anObject;

+ (instancetype)notificationWithName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;

- (instancetype)initWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo;

发布通知

通知中心(NSNotificationCenter)提供了相应的方法来帮助发布通知

- (void)postNotification:(NSNotification *)notification;

发布一个notification通知,可在notification对象中设置通知的名称通知发布者额外信息


- (void)postNotificationName:(NSString *)aName object:(id)anObject;

发布一个名称为aName的通知,anObject为这个通知的发布者


- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;

发布一个名称为aName的通知,anObject为这个通知的发布者,aUserInfo为额外信息


注册通知监听器

通知中心(NSNotificationCenter)提供了方法来注册一个监听通知的监听器(Observer)

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;

observer:监听器,即谁要接收这个通知

aSelector:收到通知后,回调监听器的这个方法,并且把通知对象当做参数传入

aName:通知的名称。如果为nil,那么无论通知的名称是什么,监听器都能收到这个通知

anObject:通知发布者。如果为anObjectaName都为nil,监听器都收到所有的通知  

- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block;

name:通知的名称

obj:通知发布者

block:收到对应的通知时,会回调这个block

queue:决定了block在哪个操作队列中执行,如果传nil,默认在当前操作队列中同步执行

取消注册通知监听器

通知中心不会保留(retain)监听器对象,在通知中心注册过的对象,必须在该对象释放前取消注册。否则,当相应的通知再次出现时,通知中心仍然会向该监听器发送消息。因为相应的监听器对象已经被释放了,所以可能会导致应用崩溃


通知中心提供了相应的方法来取消注册监听器

- (void)removeObserver:(id)observer;

- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;


一般在监听器销毁之前取消注册(如在监听器中加入下列代码):

- (void)dealloc {

//[super dealloc];  ARC中需要调用此句

    [[NSNotificationCenter defaultCenterremoveObserver:self];

}


通知和代理的选择

共同点

利用通知和代理都能完成对象之间的通信

(比如A对象告诉D对象发生了什么事情A对象传递数据给D对象)


不同点

代理 : 一对一关系(1个对象只能告诉1个对象发生了什么事情)

通知 : 多对多关系(1个对象能告诉N个对象发生了什么事情1个对象能得知N个对象发生了什么事情)  

键盘通知

我们经常需要在键盘弹出或者隐藏的时候做一些特定的操作,因此需要监听键盘的状态


键盘状态改变的时候,系统会发出一些特定的通知

UIKeyboardWillShowNotification // 键盘即将显示

UIKeyboardDidShowNotification // 键盘显示完毕

UIKeyboardWillHideNotification // 键盘即将隐藏

UIKeyboardDidHideNotification // 键盘隐藏完毕

UIKeyboardWillChangeFrameNotification // 键盘的位置尺寸即将发生改变

UIKeyboardDidChangeFrameNotification // 键盘的位置尺寸改变完毕

系统发出键盘通知时,会附带一下跟键盘有关的额外信息(字典),字典常见的key如下:

UIKeyboardFrameBeginUserInfoKey // 键盘刚开始的frame

UIKeyboardFrameEndUserInfoKey // 键盘最终的frame(动画执行完毕后)

UIKeyboardAnimationDurationUserInfoKey // 键盘动画的时间

UIKeyboardAnimationCurveUserInfoKey // 键盘动画的执行节奏(快慢)


UIDevice通知

UIDevice类提供了一个单粒对象,它代表着设备,通过它可以获得一些设备相关的信息,比如电池电量值(batteryLevel)、电池状态(batteryState)、设备的类型(model,比如iPod、iPhone等)、设备的系统(systemVersion)


通过[UIDevice currentDevice]可以获取这个单粒对象


UIDevice对象会不间断地发布一些通知,下列是UIDevice对象所发布通知的名称常量:

UIDeviceOrientationDidChangeNotification // 设备旋转

UIDeviceBatteryStateDidChangeNotification // 电池状态改变

UIDeviceBatteryLevelDidChangeNotification // 电池电量改变

UIDeviceProximityStateDidChangeNotification // 近距离传感器(比如设备贴近了使用者的脸部)        

ios通知机制

阅读数 779

ios通知机制

博文 来自: u012894631

iOS通知中心的使用

博文 来自: haoxindasoft

iOS NSNotification 通知机制

博文 来自: ccflying88

iOS 本地通知

阅读数 976

ios本地通知初体验

博文 来自: u010123208
没有更多推荐了,返回首页