Objective-C:模拟按钮点击事件理解代理模式
OC中的协议(Protocol)和和.NET中的接口(Interface)类似,简单来讲,就是一系列方法的列表,其中声明的方法可以被任何类实现。不同的是,在.NET中,如果某个类实现了一个接口,就必须实现这个接口中声明的所有方法;但在OC中,可以不实现协议中声明的所有方法,需要用到某些功能,就去实现对应的方法即可。
这种模式一般称为代理模式。在iOS和OS X开发中,Apple采用了大量的代理模式来实现MVC中View(UI控件)和Controller(控制器)的解耦。
监听思想:如果想让某个对象能够监听某个控件的动作,就可以让这个对象实现特定的协议,好抽象~。说人话,比如,如果想要用户点击某个按钮后,APP能够做一些事情(例如返回到上一个界面),需要给按钮设置监听器监听按钮的点击事件,然后“返回上一个界面”这个事情就交给监听器去做。因为需要作出特定的响应,所以不是所有的对象都可以成为按钮的监听器的。那什么样的对象才能充当按钮的监听器呢?条件是:实现某个协议里的方法(这个协议一般在需要被监听的对象内部声明)。
以监听按钮的点击事件为例:
Button:我可以被点,谁来监听我啊?
//Button.h头文件
//和分类Catelogy一样,协议也可以写在其他文件中,但一般写在.h文件中
#import <Foundation/Foundation.h>
@class Button;
// <>代表实现某个协议
@protocol ButtonDelegate <NSObject>//协议也可以实现其他协议,定义的该协议实现了最根本的协议NSObject
- (void)onClick:(Button *)btn;//这个方法是留给需要实现该协议的对象去调用
@end @interface Button : NSObject
@property (nonatomic, retain) id<ButtonDelegate> delegate;//按钮应提供一个属性来设置监听器,delegate就是按钮的监听器,不然按钮和其监听器无法通信 //不需要线程安全,故nonatomic;它是个对象,最好用retain;不知道声明类型的对象会成为自己的监听器,故id
- (void)click;//这个方法是按钮自己调用的,用来模拟点击按钮事件,调用该方法相当于点击了按钮 @end
//Button.m实现文件
#import "Button.h"
@implementation Button
- (void)dealloc {
[_delegate release];
[super dealloc];
}
- (void)click {
// 如果_delegate实现了onClick:这个方法
if ( [_delegate respondsToSelector:@selector(onClick:)] ) {
// 按钮被点击了,就应该通知监听器.并且告诉监听器哪个按钮被点击了
[_delegate onClick:self];
} else {
NSLog(@"监听器并没有实现onClick:方法");
}
}
@end
ButtonListerner:我想监听你呢!
//ButtonListerner.h头文件
#import <Foundation/Foundation.h>
// 对协议进行提前声明,跟@class的用途是一致的
@protocol ButtonDelegate;
@interface ButtonListener : NSObject <ButtonDelegate>//要做Button的监听器,就要实现我Button定的协议
@end
//ButtonListerner.m实现文件
#import "ButtonListener.h"
#import "Button.h" @implementation ButtonListener
- (void)onClick {//实现Button协议里为我准备的onClick方法
NSLog(@"ButtonListener已经监听到按钮被点击了");
}
@end
main:我来检查下,看ButtonListerner可不可以监听Button了。
//main函数中实现对按钮的监听
#import <Foundation/Foundation.h>
#import "Button.h"
#import "ButtonListener.h" int main(int argc, const char * argv[])
{
@autoreleasepool {
// 初始化一个按钮
Button *button = [[[Button alloc] init] autorelease];
// 初始化一个按钮的监听器
ButtonListener *listener = [[[ButtonListener alloc] init] autorelease];// 设置按钮的监听器
button.delegate = listener;
NSLog(@"button:%@", button);
// 点击按钮
[button click];
}
return ;
}
main函数运行后打印的结果是:ButtonListener已经监听到按钮被点击了。
这表明ButtonListerner里的onClick方法被调用了,奇怪,在main函数中我们并没有调用这个方法呀。这就是我们想要的结果:当“[button click];”执行(前面说过,这表示Button被点击了),然后某些事情就自动处理了(比如这里ButtonListerner里的onClick方法)。再啰嗦几句吧。
理解这个监听过程,主要注意这两个方法:
- - (void)click方法:这个方法是按钮自己实现的,相当于事件的发生;
- - (void)onClick:方法:这个方法是代理去实现的。
上面的例子显示了当按钮Button调用自己的click方法时,跟着按钮的代理ButtonListener的onClick方法也被调用了,这样就达到了监听按钮点击事件的目的。也就是说,当我们想让一个按钮被点击后,其他地方能够进行一些各种各样的操作时,我们不需要在按钮内部去实现,在它的代理对象内部去实现就可以啦,这不就达到了解耦的目的嘛。
协议也可以写在一个新建的协议文件里,并且实现该协议的对象可以对该协议里的方法选择性地去实现。哪些方法是必须实现的,哪些方法又是可以选择性实现的呢?这取决于该方法是如何被声明的。
定义两个协议:
//StudyDelegate.h 协议文件
#import <Foundation/Foundation.h> @protocol StudyDelegate <NSObject>
// 默认就是@required
- (void)test3; // @required表示必须实现的方法
// 虽然字面上说是必须实现,但是编译器并不强求某个类进行实现
@required
- (void)test; - (void)test1; // @optional表示可选(可实现\也可不实现)
@optional
- (void)test2;
@end
//LearnDelegate.h协议文件
#import <Foundation/Foundation.h> @protocol LearnDelegate <NSObject> @end
定义一个学生类,该类的对象用来实现上面的协议:
//Student.h
#import <Foundation/Foundation.h>
@protocol StudyDelegate, LearnDelegate; @interface Student : NSObject <Study, Learn> @end
//Student.m
#import "Student.h"
#import "StudyDelegate.h"
#import "LearnDelegate.h" @implementation Student @end
判断Student类型的对象是否实现了协议:
#import <Foundation/Foundation.h>
#import "Student.h" @protocol StudyDelegate; int main(int argc, const char * argv[])
{ @autoreleasepool {
Student *stu = [[[Student alloc] init] autorelease]; // 注意:OC是弱语法的,对类型要求不严格
// NSString *stu = [[[Student alloc] init] autorelease];
// [stu stringByAbbreviatingWithTildeInPath]; // conformsToProtocol:判断是否遵守了某个协议
if ([stu conformsToProtocol:@protocol(StudyDelegate)]) {
NSLog(@"Student遵守了StudyDelegate这个协议");
} // respondsToSelector:判断是否实现了某个方法
if ( ![stu respondsToSelector:@selector(test)] ) {
NSLog(@"Student没有实现test这个方法");
}
}
return ;
}
运行结果是:Student遵守了StudyDelegate这个协议;Student没有实现test这个方法;验证了刚才的说法:可以遵守协议,但不实现该协议里声明的方法。遵守协议即实现协议。
注意,selector就相当于方法(消息),发送消息就是调用方法。
Objective-C:模拟按钮点击事件理解代理模式的更多相关文章
- C++用PostMessage模拟按钮点击
有时我们可能会在某个程序中用到模拟按钮点击事件. 本文中的例子在MFC程序中调试通过,duilib的没试过,还需探索 不多说,上代码: #include "stdafx.h" #i ...
- js触发按钮点击事件
js触发按钮点击事件 博客分类: javascript 模拟JS触发按钮点击功能 <html> <head> <title>usually function&l ...
- css3模拟jq点击事件
还是这个梗,收好冷.今天是一个css3模拟jq点击事件,因为我发现,css3中没有类似于,js的点击事件,那么,可不可以仿照 jq的效果,类似的做一个呢?主要用到,input里面的radio 单选按钮 ...
- 按钮点击事件,打开新的Activity
按钮点击事件,打开新Activity, 打开网页 findViewById(R.id.btnStartBAty).setOnClickListener(new View.OnClickListener ...
- Javascript之三种按钮点击事件
学习Javascript必须要先掌握基本的事件方法和语法,这些都是我们学过的也是最基本的.以前忘了总结,所以现在回顾,综合地总结一下,温故而知新. Javascript有三种按钮点击事件,分别为ale ...
- 【转】Android开发20——单个监听器监听多个按钮点击事件
原文网址:http://woshixy.blog.51cto.com/5637578/1093936 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律 ...
- 【Android】按钮点击事件的常用写法
学习总结: 最近学习了Android点击事件的常用写法.点击事件会触发监听对象身上的回调,常用写法有以下四种: 方法一:使用匿名内部类. public class MainActivity exten ...
- ButtonAddListener监听按钮点击事件
ButtonAddListener监听按钮点击事件 using UnityEngine; using System.Collections; using UnityEngine.UI; using U ...
- js和jquery触发按钮点击事件
js触发按钮点击事件 function load(){ //下面两种方法效果是一样的 document.getElementById("target").onclick(); do ...
随机推荐
- HDU 1698 Just a Hook(线段树成段更新)
Just a Hook Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- 认识DOS
实验一.认识DOS实验 专业 物联网工程 姓名 叶慧敏 学号 201306104139 一. 实验目的 (1)认识DOS: (2)掌握命令解释程序的原理: (3)掌握简单的DOS调用方法: (4)掌 ...
- linux设备驱动编写_tasklet机制(转)
在编写设备驱动时, tasklet 机制是一种比较常见的机制,通常用于减少中断处理的时间,将本应该是在中断服务程序中完成的任务转化成软中断完成. 为了最大程度的避免中断处理时间过长而导致中断丢失,有时 ...
- dateTimePicker的使用,时间控件
<li> <label>促销时间<span class="imprt">*</span></label> <inp ...
- Java实现分页数据获取CachedRowSet
步骤 1.加载驱动 2.连接数据库 3.创建ResultSet 4.创建CacheRowSet 5.设置并获取分页数据 6.执行查询,展示数据 package ch13; import javax.s ...
- z-score
标准分数(standard score)也叫z分数(z-score),是一个分数与平均数的差再除以标准差的过程.用公式表示为: z=(x-μ)/σ.其中x为某一具体分数, μ为平均数,σ为标准差. Z ...
- Android照相机模块编程 照片颠倒问题及查询摄像头参数问题的解决
这两天编程弄Android照相机模块,设置好各种参数后,发现预览的时候,照片是颠倒了,不是上下颠倒而是颠倒90°. 我的手机是华为U9200,用的Android4.0.3,后来看到http://www ...
- go分页
简单的beego分页功能代码 一个简单的beego分页小插件(源代码在最下面): 支持条件查询 支持参数保留 支持自定义css样式 支持表/视图 支持参数自定义 默认为pno 支持定义生成链接的个数 ...
- ganymedssh2 java执行linux命令
需要下载ganymed-ssh2-262.jar package ganymed; import java.io.BufferedReader; import java.io.IOException; ...
- Spring Boot 以 jar 包方式运行在后台
spring-boot jar 包方式启动: 首先,为了防止和常用的 Tomcat 8080 端口冲突,将 Spring-boot 项目的端口号设置为 9090. 具体方法:在 application ...