在 iPhone 中,每个 UIControl 都有预定义的委托方法,但是我们将如何创建自己的自定义委托方法
3 回答
在你的头文件之前@interface
,插入
@protocol YourDelegate <NSObject>
@optional
- (void) anOptionalDelegateFunction;
@required
- (void) aRequiredDelegateFunction;
@end
和下@interface
@property (nonatomic, assign) id<YourDelegate> delegate;
// Remember to synthesize in implementation file
现在你可以调用你的 .m 文件
[delegate aRequiredDelegateFunction];
在委托中
- 像往常一样包含
<YourDelegate>
在 .h 文件中 - 在 .m 中,将具有自定义委托的类的委托属性分配给
self
创建自定义委托和协议 iOS | Swift 和 Objective-C
协议
协议是指定代理将实现的接口的方法列表。我们可以使用两种委托:Option 和 Required。它们很容易解释,但不同之处在于Required会抛出一个错误,让你知道你的类不符合协议。默认情况下还需要协议方法,因此如果您希望它是可选的,请不要忘记该可选关键字。如果您使用的是 swift,如果您需要可选方法,还需要添加 @objc 前缀。
迅速
//
// MyTimer.swift
// SwiftProtocol
//
// Created by Barrett Breshears on 10/11/14.
// Copyright (c) 2014 Sledge Dev. All rights reserved.
//
import UIKit
// set up the MyTimerDelegate protocol with a single option timer function
@objc protocol MyTimerDelegate{
optional func timerFinished()
}
class MyTimer: UIViewController {
// this is where we declare our protocol
var delegate:MyTimerDelegate?
// set up timer variables and labels
var timer:NSTimer! = NSTimer()
var labelTimer:NSTimer! = NSTimer()
var timerLabel:UILabel! = UILabel()
var timerCount = 0
var duration = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
timerLabel = UILabel(frame: self.view.frame)
timerLabel.textAlignment = NSTextAlignment.Center
self.view.addSubview(timerLabel)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func startTimer(timerDuration:Double){
self.duration = Int(timerDuration)
timerLabel.text = String(format: "%d", duration)
timer = NSTimer.scheduledTimerWithTimeInterval(timerDuration, target: self, selector: Selector("timerFired:"), userInfo: nil, repeats: false)
labelTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("updateLabel:"), userInfo: nil, repeats: true)
}
timer.invalidate()
}
if(labelTimer.valid){
labelTimer.invalidate()
}
// ************************************** \\
// ************************************** \\
// This is the important part right here
// we want to call our protocol method
// so the class implementing this delegate will know
// when the timer has finished
// ************************************** \\
// ************************************** \\
delegate?.timerFinished!()
}
func updateLabel(timer:NSTimer){
duration = duration - 1
timerLabel.text = String(format: "%d", duration)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
这是一个非常简单的例子,但这就是正在发生的事情。UIViewController 有一个启动计时器方法,它设置了两个计时器:一个在总时间完成时触发,另一个每秒触发一次以更新计时器标签。当总持续时间计时器完成时,将调用 timerFired 方法,这就是我们运行委托的 timerFinished 方法的地方。现在让我们用 Objective-C 做同样的事情。
Objective-C
//
// MyTimer.h
// ObjectIveCProtocol
//
// Created by Barrett Breshears on 10/11/14.
// Copyright (c) 2014 Sledge Dev. All rights reserved.
//
#import
// set up the MyTimerDelegate protocol with a single option timer finished function
@protocol MyTimerDelegate
@optional
-(void)timerFinished;
@end
@interface MyTimer : UIViewController
// this is where we declare our protocol
@property (nonatomic, strong) id delegate;
// set up timer variables and labels
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, strong) NSTimer *labelTimer;
@property (nonatomic, strong) UILabel *timerLabel;
@property (nonatomic, assign) int timerCount;
@property (nonatomic, assign) int duration;
- (void)startTimer:(float)duration;
@end
//
// MyTimer.m
// ObjectIveCProtocol
//
// Created by Barrett Breshears on 10/11/14.
// Copyright (c) 2014 Sledge Dev. All rights reserved.
//
#import "MyTimer.h"
@interface MyTimer ()
@end
@implementation MyTimer
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_timer = [[NSTimer alloc] init];
_labelTimer = [[NSTimer alloc] init];
_timerCount = 0;
_duration = 0;
_timerLabel = [[UILabel alloc] initWithFrame:self.view.frame];
[self.view addSubview:_timerLabel];
[_timerLabel setTextAlignment:NSTextAlignmentCenter];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)startTimer:(float)duration{
_duration = (int)duration;
_timerLabel.text = [NSString stringWithFormat:@"%d", _duration];
_timer = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:@selector(timerFired:) userInfo:nil repeats:NO];
_labelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateLabel:) userInfo:nil repeats:YES];
}
- (void)timerFired:(NSTimer *)timer {
if ([_timer isValid]) {
[_timer invalidate];
}
_timer = nil;
if ([_labelTimer isValid]) {
_labelTimer invalidate];
}
_labelTimer = nil;
// ************************************** \\
// This is the important part right here
// we want to call our protocol method here
// so the class implementing this delegate will know
// when the timer has finished
// ************************************** \\
[_delegate timerFinished];
}
- (void)updateLabel:(NSTimer *)timer{
_duration = _duration - 1;
_timerLabel.text = [NSString stringWithFormat:@"%d",
_duration];
}
@end
所以同样的事情只是语法不同。UIViewController 有一个启动计时器方法,它设置了两个计时器:一个在总时间完成时触发,另一个每秒触发一次以更新计时器标签。当总持续时间计时器完成时,将调用 timerFired 方法,这就是我们运行委托的 timerFinished 方法的地方。
代表们
现在我们已经设置了所有协议,我们所要做的就是实现它们。我们将通过创建一个委托来做到这一点。委托是一个符合协议的变量,类通常使用它来通知事件,在这种情况下是计时器完成。为此,我们将协议添加到类声明中,让我们的类知道它必须遵守委托。然后我们将委托方法添加到我们的类中。
迅速
//
// ViewController.swift
// Swift-Protocol
// Created by Barrett Breshears on 10/11/14.
// Copyright (c) 2014 Sledge Dev. All rights reserved.
import UIKit
// add our MyTimerDelegate to our class
class ViewController: UIViewController, MyTimerDelegate {
var timer:MyTimer = MyTimer()
override func viewDidLoad() {
super.viewDidLoad()
timer.view.frame = self.view.frame
// ************************ \\
// This is where we let the delegate know
// we are listening for the timerFinished method
// ************************ \\
timer.delegate = self
self.view.addSubview(timer.view)
timer.startTimer(10.0)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// ************************ \\
// This is where our delegate method is fired
// ************************ \\
func timerFinished(){
timer.startTimer(10.0)
println("Hey my delegate is working")
}
}
所以这里重要的是我们将 timer.delegate 设置为 self 以便调用 ViewController 的方法 timerFinished() 类。
Objective-C
//
// ViewController.h
// ObjectIveCProtocol
//
// Created by Barrett Breshears on 10/10/14.
// Copyright (c) 2014 Sledge Dev. All rights reserved.
#import
#import "MyTimer.h"
// add our MyTimerDelegate to our class
@interface ViewController : UIViewController
@property (nonatomic, strong) MyTimer *timer;
@end
// ViewController.m
// ObjectIveCProtocol
// Created by Barrett Breshears on 10/10/14.
// Copyright (c) 2014 Sledge Dev. All rights reserved.
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_timer = [[MyTimer alloc] init];
_timer.view.frame = self.view.frame;
_timer.delegate = self;
[self.view addSubview:_timer.view];
[_timer startTimer:10.0];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)timerFinished{
[_timer startTimer:10.0];
NSLog(@"Hey my delegate is working!");
}
@end
当我们运行代码时,我们看到计时器标签被添加并设置为 10 秒计时器。它倒计时,当它到达 0 时通知视图控制器,重新启动计时器并打印“嘿,我的代表正在控制台中工作”。
如果您对代码有任何疑问或发现本教程有帮助,请在下面的评论中告诉我!我很感激反馈。也不要忘记在推特上关注我。我一直在寻找 iOS 开发者来发推文。
如果您想关注允许,您可以在此处从 GitHub 下载项目:
https://github.com/barrettbreshears/objective-c-protocol
或者,
在您的班级中创建一个 id 对象委托。创建一个 getter 和 setter,以便其他类可以将自己设置为委托。在您的班级中添加以下内容:
@interface MyClass (Private)
-(void)myDelegateMethod;
@end
然后在你想要回调到委托类的任何函数中执行以下操作:
if ( [delegate respondsToSelector:@selector(myDelegateMethod)] ) {
[delegate myDelegateMethod];
}