[原创]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

[原创]obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用,布布扣,bubuko.com

时间: 2024-12-17 22:45:16

[原创]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类里的

obj-c编程15[Cocoa实例03]:MVC以及归档化示例

前面的博文里介绍了归档和解档,这里我们把它实际应用到一个简单的代码中去,将它作为一个多文档应用程序的打开和保存的背后支持.另外这里介绍一下MVC思想,这个在任何语言里都会有,它是一种设计思想,主要可以概括为一个程序由3部分组成: 1 模式:是程序的数据支持: 2 视图:是程序的表示支持: 3 控制:连接模式和视图,将程序构为一个整体: Cocoa框架中对MVC提供了非常好的支持,你只需要写很少的代码就可以完成一个程序的MVC绑定了.下面的例子中,我生成一个基于多文档的程序,使用了NSArrayC

ConfigParser 实例 02

# -*- coding: cp936 -*- IP1=""  #扫描IP IP2=""   #当前已经扫到的IP INITXT="IP.ini"  #INI文件名字 import ConfigParser def ini_get():  #读取INI try: global IP1 global IP2 global INITXT config = ConfigParser.ConfigParser() config.readfp(open(I

并发编程 15—— 线程池 之 原理二

Java并发编程实践 目录 并发编程 01—— ConcurrentHashMap 并发编程 02—— 阻塞队列和生产者-消费者模式 并发编程 03—— 闭锁CountDownLatch 与 栅栏CyclicBarrier 并发编程 04—— Callable和Future 并发编程 05—— CompletionService : Executor 和 BlockingQueue 并发编程 06—— 任务取消 并发编程 07—— 任务取消 之 中断 并发编程 08—— 任务取消 之 停止基于线

零元学Expression Blend 4 - Chapter 15 用实例了解互动控制项「Button」I

原文:零元学Expression Blend 4 - Chapter 15 用实例了解互动控制项「Button」I 本章将教大家如何更改Button的预设Template,以及如何在Button内设置动画. ? 本章将教大家如何更改Button的预设Template,以及如何在Button内设置动画. ? ? ? 01 开启一个新专案,并且置入一个Button,调整到适当大小 ? 在Properties->可以调整Button的外观,基本设定都跟先前的教学雷同 不熟的人请看如何用Blend制作一

1036. 跟奥巴马一起编程(15)

1036. 跟奥巴马一起编程(15) 美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014年底,为庆祝"计算机科学教育周"正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形.现在你也跟他一起画吧! 输入格式: 输入在一行中给出正方形边长N(3<=N<=20)和组成正方形边的某种字符C,间隔一个空格. 输出格式: 输出由给定字符C画出的正方形.但是注意到行间距比列间距大,所以为了让结果看上去更像正方形,我们

PAT-乙级-1036. 跟奥巴马一起编程(15)

1036. 跟奥巴马一起编程(15) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形.现在你也跟他一起画吧! 输入格式: 输入在一行中给出正方形边长N(3<=N<=20)和组成正方形边的某种字符C,间隔一个

Java Swing界面编程(15)---JScrollPane

在一般的图形界面中,如果显示的区域不够大,往往会出现滚动条以方便用户的浏览,在Swing中JScrollPane的主要的功能就是为了显示的内容加入水平滚动条. package com.beyole.util; import java.awt.Container; import java.io.File; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.sw

python高级编程之装饰器02

#装饰器02 #参数检查 #主要是用在接收或者返回函数,在特定上下文执行时可能有用 #例如:有一个函数通过XML-RPC调用,python将不能和静态类语言中一样直接提供它的完整签名,当XML-RPC客户要求函数签名时,就需要这样的能力 """ xml-rpc相关学习:http://zh.wikipedia.org/wiki/XML-RPC """ #装饰器能提供这种签名类型,并确保输入输出与此有关,如下 from itertools impor