• [原创]obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用


    原文链接:obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用

        我们在第16和第17篇中分别介绍了obj-c的KVC与KVO特性,当时举的例子比较fun,太抽象,貌似和实际不沾边哦。那么下面我们就用一个实际中的例子来看看KVC与KVO是如何运用的吧。

        该例中用到了3种新的控件类型:NSTableView、NSSlider以及简单的NSTextField类型。按说不能再在Random类里添加不沾边的新增功能了,但是为了简单,我还是把所有东西都放在Random类里喽。程序运行时界面如下:

    大家可以看到左上角的文本域控件用来显示当前音量,因为它和Random类里的str_volume(或者是str_vol_way2以及str_vol_way3)属性做了绑定,所以它会即时更新音量变化的数值;而文本域控件下方的刻度条控件可以让用户更改音量大小(从0 到 100),它和Random类的属性volume绑定起来,所以改变刻度就会带来volume属性值的变化,相当于对volume属性做写者操作哦。有童鞋可能不明白文本域是如何随着刻度条值的变化而变化的,毕竟他们绑定的不是一个属性啊!

        其实我在这里用了KVO的概念,不过这里我用自己监视的是自己的属性啊:在Random的init方法中设置被观察者为self,而观察者也是self,观察的KeyPath为@"volume",于是乎若刻度条将volume改变(因为它和volume绑定,所以它刻度的改变会导致volume的改变,上面已经说了,会调用volume的写者方法。),则self,也就是Random的对象自己会收到通知。不过这里要注意,不能够直接在通知回调方法中直接写:str_volume = [新值] ,因为你这样没有调用str_volume的写者方法,你是直接改实例变量本身了,这样文本域不会有变化的:因为文本域控件也对str_volume做了KVO,而且该KVO只能监视到str_volume被写者方法改变的情况,你直接改它实例变量,自然没有反应喽。要解决这个问题,可以有3种方法:

    1 将str_volume定义在interface,并声明属性,然后在implementation里做@synthesize str_volume,这样我们用[self setStr_volume或self.str_volume的方法(实例变量str_volume的写者方法)修改,自然会通知外部监控器。

     

    2 手动发送通知,告知属性被改了,这也是str_vol_way2的方法;

     

    3 用属性的KVC方式修改其值,这也是str_vol_way3的方法啊(注意:str_vol_way3没有外部接口哦!)。

    然后在人语发声之前用speech的setVolume方法应用当前的音量大小就可以啦,不过注意该方法setVolume的参数是浮点数,取值范围为0.0 - 1.0,所以我在代码中要除以100啊!

        再看窗口右上方的列表视图控件,也有几个地方要注意:

    1 它是由几个控件组成的,鼠标要多选几次才能选中里面的控件,如果控件选的不对,可能就找不到要设置属性喽:

     

    2 其Connections Inspector中要连接2个地方:dataSource和delegate。前者用来做数据源的代理,后者做其本身动作的代理哦。如果不设置前者则没有数据源,就没东西显示啊;同理,若不设置后者就无法响应用户的动作哦。切记切记。这里再说说代理,代理就是你调用别的类,可是有些事还是你自己最清楚,所以别的类的有些操作还是得返回来问你自己啊。比如列表视图控件对于[col,row]位置显示的内容是不知道的,所以你必须以回调方法的方式告诉它;再者,如果它的当前选中行发生变化了,他也不知道如何处理,所以也要问你,等于是一个当前行改变的事件发生了,Random类必须提供事件处理函数哦。

        最后,NSTableView控件还是要按老规矩和Random类连接起来啊,就在其Referencing Outlets里哦;也就是说它和Random一共发生了3种显式关系(想歪的自觉面壁去偷笑)如下图所示:

        好了,上面把主要的问题都大致说过了,啥也不说鸟,下面的都在代码里喽(在Cocoa实例02的代码基础上修改而来):

     1 //
     2 //  Random.h
     3 //  mac_test
     4 //
     5 //  Created by kinds on 14-7-4.
     6 //  Copyright (c) 2014年 kinds. All rights reserved.
     7 //
     8 
     9 #import "comm.h"
    10 #import <Cocoa/Cocoa.h>
    11 
    12 @interface Random : NSObject {
    13     IBOutlet NSTextField *text_field;
    14     IBOutlet NSTableView *tab_view;
    15     NSString *str_volume;
    16 }
    17 
    18 @property NSString *str_volume;
    19 
    20 -(IBAction)seed:(id)sender;
    21 -(IBAction)generate:(id)sender;
    22 
    23 @end
      1 //
      2 //  Random.m
      3 //  mac_test
      4 //
      5 //  Created by kinds on 14-7-4.
      6 //  Copyright (c) 2014年 kinds. All rights reserved.
      7 //
      8 
      9 #import "Random.h"
     10 
     11 @implementation Random{
     12     NSSpeechSynthesizer *speech;
     13     NSArray *voices;
     14     NSNumber *volume;
     15     NSString *str_vol_way2;
     16     NSString *str_vol_way3;
     17 }
     18 
     19 @synthesize str_volume;
     20 
     21 -(id)init{
     22     self = [super init];
     23     if(self){
     24         speech = [[NSSpeechSynthesizer alloc] initWithVoice:nil];
     25         voices = [NSSpeechSynthesizer availableVoices];
     26         msg(@"%@",voices);
     27         
     28         volume = [NSNumber numberWithInt:0];
     29         str_volume = [NSString stringWithFormat:@"音量:%@",volume];
     30         str_vol_way2 = str_vol_way3 = str_volume;
     31         [self addObserver:self forKeyPath:@"volume" 
     32                   options:NSKeyValueObservingOptionNew context:nil];
     33     }
     34     return self;
     35 }
     36 
     37 -(void)observeValueForKeyPath:(NSString *)key_path ofObject:(id)obj 
     38     change:(NSDictionary *)change context:(void *)context{
     39         NSNumber *new_val = [change objectForKey:NSKeyValueChangeNewKey];
     40         msg(@"volume is change to %@",new_val);
     41         //str_volume = @"A";
     42         self.str_volume = [NSString stringWithFormat:@"音量:%i",[new_val intValue]];
     43         
     44         //syn way 2
     45         [self willChangeValueForKey:@"str_vol_way2"];
     46         str_vol_way2 = str_volume;
     47         [self didChangeValueForKey:@"str_vol_way2"];
     48         //syn way 3
     49         [self setValue:str_volume forKey:@"str_vol_way3"];
     50 }
     51 
     52 -(void)set_voice{
     53     int idx = (int)(random() % [voices count]);
     54     [speech setVoice:[voices objectAtIndex:(NSUInteger)idx]];
     55 }
     56 
     57 -(IBAction)generate:(id)sender{
     58     int i = (int)(random() % 100000000000) + 1;
     59     msg(@"i = %d",i);
     60     [text_field setIntValue:i];
     61     [self set_voice];
     62     //[speech setVolume:[volume floatValue]];
     63     [speech startSpeakingString:[NSString stringWithFormat:@"%i",i]];
     64 }
     65 
     66 -(IBAction)seed:(id)sender{
     67     srandom((unsigned)time(NULL));
     68     NSString *str = @"the seed is reseted!";
     69     [text_field setStringValue:str];
     70     [speech startSpeakingString:str];
     71 }
     72 
     73 -(void)awakeFromNib{
     74     NSDate *now = [NSDate date];
     75     [text_field setObjectValue:now];
     76 }
     77 
     78 -(NSInteger)numberOfRowsInTableView:(NSTableView *)tv{
     79     return (NSInteger)[voices count];
     80 }
     81 
     82 -(id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)col 
     83 row:(NSInteger)row{
     84     NSString *v = [voices objectAtIndex:row];
     85     return v;
     86 }
     87 
     88 -(void)tableViewSelectionDidChange:(NSNotification *)notification{
     89     NSInteger row = [tab_view selectedRow];
     90     if(row == -1) return;
     91     
     92     NSString *str_voice = [voices objectAtIndex:row];
     93     [speech setVoice:str_voice];
     94     [speech setVolume:[volume floatValue]/100];
     95     [speech startSpeakingString:@"test one time!!!测试一下哦!!!"];
     96     msg(@"new voice = %@",str_voice);
     97 }
     98 
     99 -(void)dealloc{
    100     [self removeObserver:self forKeyPath:@"volume"];
    101 }
    102 
    103 
    104 @end
  • 相关阅读:
    request.getAttribute()和 request.getParameter()的区别
    jquery中$.get()提交和$.post()提交有区别吗?
    jQuery有几种选择器?
    jQuery 库中的 $() 是什么?
    JavaScript内置可用类型
    MySQL数据库中,常用的数据类型
    简单叙述一下MYSQL的优化
    什么是JDBC的最佳实践?
    Vue官网教程-条件渲染
    Vue官网教程-Class与Style绑定
  • 原文地址:https://www.cnblogs.com/hopy/p/3829946.html
Copyright © 2020-2023  润新知