Delegation

UITextField

- (void)loadView
{
    CGRect frame = [UIScreen mainScreen].bounds;
    BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] initWithFrame:frame];

    CGRect textFieldRect = CGRectMake(40, 70, 240, 30);
    UITextField *textField = [[UITextField alloc] initWithFrame:textFieldRect];

    // Setting the border style on the text field will allow us to see it more easily
    textField.borderStyle = UITextBorderStyleRoundedRect;
    [backgroundView addSubview:textField];

    self.view = backgroundView;
}

UIResponder

UIResponder is an abstract class in the UIKit framework. It is the superclass of three classes that you have already encountered:

  • UIView
  • UIViewController
  • UIApplication

UIResponder是个抽象类,UIView,UIViewController和UIApplication都实现了此类。

UIResponder defines methods for handling (or “responding to”) events: touch events, motion events (like a shake), and remote control events (like pausing or playing). Subclasses override these methods to customize how they respond to events.

UIResponder定义了事件响应方法,响应touch, motion, remote control事件,其子类可以重写这些事件响应方法。

With touch events, it is obvious which view the user has touched. Touch events are sent directly to that view.

What about the other types of events? The UIWindow has a pointer called firstResponder which indicates who should respond to the other types of events. When you select a text field, for example, the window moves its firstResponder pointer to that text field. Motion and remote control events are sent to the first responder.

touch事件会直接发送给被触摸的视图。
UIWindow中有个指针叫firstResponder,来指明谁来响应motion, remote control事件。当选中一个text field,firstResponder指针会指向这个text field。

When a text field or a text view becomes firstResponder, it shows its keyboard. When it loses first responder status, it hides its keyboard. If you want one of these views to become first responder, you send it the message becomeFirstResponder and the keyboard appears. When you want to hide the keyboard, you send it the message resignFirstResponder.

当text filed变成firstResponder,会显示键盘,当其不再是firstResponder,键盘隐藏。
如果想让某视图变成firstResponder,可以调用该视图的becomeFirstResponder,反之调用resignFirstResponder

Keyboard

The keyboard’s appearance is determined by a set of the UITextField’s properties called UITextInputTraits.

property description
autocapitalizationType This determines how capitalization is handled. The options are none, words, sentences, or all characters.
autocorrectionType This will suggest and correct unknown words. This value can be YES or NO.
enablesReturnKeyAutomatically This value can be YES or NO. If set to yes, the return key will be disabled if no text has been typed. As soon as any text is entered, the return key becomes enabled.
keyboardType This determines the type of keyboard that will be displayed. Some examples are the ASCII keyboard, email address keyboard, number pad, and the URL keyboard.
secureTextEntry Setting this to YES makes the text field behave like a password field, hiding the text that is entered.
- (void)loadView
{
    CGRect frame = [UIScreen mainScreen].bounds;
    BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] initWithFrame:frame];

    CGRect textFieldRect = CGRectMake(40, 70, 240, 30);
    UITextField *textField = [[UITextField alloc] initWithFrame:textFieldRect];

    // Setting the border style on the text field will allow us to see it more easily
    textField.borderStyle = UITextBorderStyleRoundedRect;
    textField.placeholder = @"Hypnotize me";
    // 设置键盘的retrun key type为Done
    // 键盘的return key:键盘输入完成后,点击return key完成输入,隐藏键盘
    textField.returnKeyType = UIReturnKeyDone;

    [backgroundView addSubview:textField];
    self.view = backgroundView;
}

Delegation pattern

You have already seen the Target-Action pattern. This is one form of callbacks that is used by UIKit: When a button is tapped, it sends its action message to its target.

A button’s life is relatively simple. For objects with more complex lives, like a text field, Apple uses the delegation pattern.

代理模式,为UITextField对象设置代理,由代理来处理UITextField的各种消息。

代理要为text filed对象实现的一些方法如下:

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField;
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField;
- (BOOL)textFieldShouldClear:(UITextField *)textField;
- (BOOL)textFieldShouldReturn:(UITextField *)textField;

设置text filed的delegate属性,指定其代理

 // BNRHypnosisViewController
- (void)loadView
{
    CGRect frame = [UIScreen mainScreen].bounds;
    BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] initWithFrame:frame];

    CGRect textFieldRect = CGRectMake(40, 70, 240, 30);
    UITextField *textField = [[UITextField alloc] initWithFrame:textFieldRect];

    // Setting the border style on the text field will allow us to see it more easily
    textField.borderStyle = UITextBorderStyleRoundedRect;
    textField.placeholder = @"Hypnotize me";
    // 设置键盘的retrun key type为Done
    textField.returnKeyType = UIReturnKeyDone;

    // 为text filed设置delegate
    textField.delegate = self;

    [backgroundView addSubview:textField];
    self.view = backgroundView;
}

Protocol

代理需要为被代理对象实现哪些方法呢?这由protocol来定义,protocol就像JAVA中的接口。

The protocol for UITextField’s delegate looks like this:

// The NSObject in angled brackets refers to the NSObject protocol and tells us 
// that UITextFieldDelegate includes all of the methods in the NSObject protocol.
@protocol UITextFieldDelegate <NSObject>

@optional
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField;
- (void)textFieldDidBeginEditing:(UITextField *)textField;
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField;
- (void)textFieldDidEndEditing:(UITextField *)textField;
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
- (BOOL)textFieldShouldClear:(UITextField *)textField;
- (BOOL)textFieldShouldReturn:(UITextField *)textField;

@end

Note that a protocol is not a class; it is simply a list of method declarations.

Methods declared in a protocol can be required or optional. By default, protocol methods are required. If a protocol has optional methods, these are preceded by the directive @optional.

Before sending an optional message, the object first asks its delegate if it is okay to send that message by sending another message, respondsToSelector:. Every object implements this method, which checks at runtime whether an object implements a given method. You can turn a method selector into a value that you can pass as an argument with the @selector() directive. For example, UITextField could implement a method that looks like this:

- (void)clearButtonTapped
{
    // textFieldShouldClear: is an optional method, so we check first
    SEL clearSelector = @selector(textFieldShouldClear:);
    // 先检查对应的方法是否存在,如果存在再调用
    if ([self.delegate respondsToSelector:clearSelector]) {
        if ([self.delegate textFieldShouldClear:self]) {
            self.text = @"";
        }
    }
}

protocol不是一个类,只是声明了一些抽像方法。
protocol中的方法默认是required,就是代理必须要实现的;可以用@optional来声明为可选的。
被代理的对象在调用protocol中声明的optional方法前,会先通过respondsToSelector:方法来确认代理是否实现了对应的optional message(OC中叫message,可以理解为java中的method)。

**
对象,代理(delegate),协议(protocol),这三者的关系要理清楚:对象(比如一个text field)有一个对应的protocol,用来定义text field对象的delegate应该实现的方法,delegate要去实现protocol中定义的方法。text field对象会去调用delegate中实现的方法。
**

But for the compiler to know to check for implementations of a protocol’s required methods, the class must explicitly state that it conforms to a protocol. This is done either in the class header file or the class extension: the protocols that a class conforms to are added to a comma-delimited list inside angled brackets in the interface declaration.

delegate要标明实现哪些protocol,可以头文件或是在class extension中声明实现的protocol,用尖括号括起来,如果有多个protocol用逗号分隔。

在头文件和class extension中的区别如之前讲到的,头文件中的是public的,class extension中的是private的。

The reason for adding it to the class extension rather than the header file is the same reason as always: add to the class extension if the information (conforming to a particular protocol in this case) does not need to be publicly visible, and add it to the header file if other objects do need to know about the information.

以下是在class extension中标明:

@interface BNRHypnosisViewController () <UITextFieldDelegate>
@end

Motion Effects

苹果设备上,在首页倾斜屏幕,可以看到首页的图标会移动。这可以通过UIInterpolatingMotionEffect来实现:

UIInterpolatingMotionEffect *motionEffect;

motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
motionEffect.minimumRelativeValue = @(-25);
motionEffect.maximumRelativeValue = @(25);
[messageLabel addMotionEffect:motionEffect];

motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
motionEffect.minimumRelativeValue = @(-25);
motionEffect.maximumRelativeValue = @(25);
[messageLabel addMotionEffect:motionEffect];

main() and UIApplication

iOS应用的程序入口,如下:

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([BNRAppDelegate class]));
    }
}

The function UIApplicationMain creates an instance of a class called UIApplication. For every application, there is a single UIApplication instance. This object is responsible for maintaining the run loop. Once the application object is created, its run loop essentially becomes an infinite loop: the executing thread will never return to main().

UIApplicationMain 方法创建了一个 UIApplication 实例,一个应用只有一个此实例,负责维护应用的run loop。

Another thing the function UIApplicationMain does is create an instance of the class that will serve as the UIApplication’s delegate. Notice that the final argument to the UIApplicationMain function is an NSString that is the name of the delegate’s class. So, this function will create an instance of BNRAppDelegate and set it as the delegate of the UIApplication object.

UIApplicationMain 方法不仅创建了UIApplication 实例,还会为其创建对应的delegate,UIApplicationMain 方法的最后一个参数就是delegate's name。

The first event added to the run loop in every application is a special “kick-off” event that triggers the application to send a message to its delegate. This message is application:didFinishLaunchingWithOptions:. You implemented this method in BNRAppDelegate.m to create the window and the controller objects used in this application.

然后application调用其代理的application:didFinishLaunchingWithOptions:方法来完成窗口及相应视图的创建,我们在此方法添加自己的视图。


本文是对《iOS Programming The Big Nerd Ranch Guide 4th Edition》第七章的总结。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,376评论 0 23
  • 大家好,我是IT修真院北京总院第24期的学员,一枚正直纯洁善良的web程序员 今天给大家分享一下,修真院官网css...
    我是一只北极熊啊阅读 6,027评论 0 3
  • 对于生活,愿我们不再蹉跎、不作妄谈 。可以发有千种期许,但也要播种一个开端;不发狠、也不看穿 。不去苦求同路与照看...
    汽球阅读 282评论 0 0
  • 忘了从什么时候起,周杰伦开始走进我的生活。我从来没有像那些疯狂的粉丝一样,把他的海报贴满整个房间,把他的每张专辑放...
    笑容女王阅读 783评论 0 6
  • 我 现在许个愿 每天早晨起床就能闻见你煮的爱心dumplings 我 现在许个愿 每天中午回来就能尝见你烧的红烧m...
    Eternity698阅读 180评论 0 2