【问题标题】:iPhone - Custom Class Won't Access MethodiPhone - 自定义类不会访问方法
【发布时间】:2009-07-24 17:12:37
【问题描述】:

我正在尝试一些 iPhone 编程,但我遇到了一些对于退伍军人来说可能相当明显的事情,但我不确定为什么会发生这种情况。我有两个 UIViewController 类,我想从另一个类访问一个方法。我在 IB 中有两个 NSObject 类与它们相关联(每个类的文件作为 UpdateClass),我正在尝试创建一个类并调用一个方法。看起来很简单,但问题是它正在调用该方法(根据 NSLog)但它没有更新标签。这是我的代码:

//UpdateClass.h
#import <Foundation/Foundation.h>

@interface UpdateClass : NSObject {
    IBOutlet UILabel *lbl1;
    IBOutlet UILabel *lbl2;
}

@property (nonatomic, retain) IBOutlet UILabel *lbl1;
@property (nonatomic, retain) IBOutlet UILabel *lbl2;

- (void)updateLabels;

@end

//UpdateClass.m

#import "UpdateClass.h"

@implementation UpdateClass

@synthesize lbl1;
@synthesize lbl2;


- (void)updateLabels {
    NSString *someWord = @"Whatever"; // This could be anything
    NSLog(@"NSObject Update");
    [lbl1 setText:someWord];
    [lbl2 setText:someWord];
}


@end

//ViewController1.h
#import <UIKit/UIKit.h>
@class UpdateClass;
@interface ViewController1 : UIViewController {
IBOutlet UIButton *button1;
NSObject *UpdateClassObject;
UpdateClass *updateClass;
}
@property (nonatomic, retain) IBOutlet UIButton *button1;
@property (nonatomic, retain) NSObject *UpdateClassObject;
@property (nonatomic, retain) UpdateClass *updateClass;
- (void)updateLabels:(id)sender;
@end

//ViewController1.m
#import "ViewController1.h"
#import "UpdateClass.h"

@implementation ViewController1
@synthesize button1;
@synthesize UpdateClassObject;
@synthesize updateClass;

- (void)viewDidLoad {
    [super viewDidLoad];
    updateClass = [[UpdateClass alloc] init];
}

- (void)updateLabels:(id)sender; { //This is connected to TouchDown on button1
    NSLog(@"Calls UpdateLabels");
    [updateClass updateLabels]; //Calls the class method
}

//ViewController2.h
#import <UIKit/UIKit.h>
@class UpdateClass;
@interface ViewController2 : UIViewController {
IBOutlet UIButton *button2;
NSObject *UpdateClassObject;
UpdateClass *updateClass;
}
@property (nonatomic, retain) IBOutlet UIButton *button2;
- (void)updateLabels:(id)sender;
@end

//ViewController2.m
#import "ViewController2.h"
#import "UpdateClass.h"

@implementation ViewController2
@synthesize button2;
@synthesize UpdateClassObject;
@synthesize updateClass;

- (void)viewDidLoad {
    [super viewDidLoad];
    updateClass = [[UpdateClass alloc] init];
}

- (void)updateLabels:(id)sender; { //This is connected to TouchDown on button2
    NSLog(@"Calls UpdateLabels");
    [updateClass updateLabels]; //Calls the class method
}

所以在 IB 中为两个视图连接了一个 NSObject。每个视图上都有一个连接到 NSObject 和文件所有者的标签(可能不需要将它们连接到两者)。当按下按钮时(在 IB 中也正确连接),标签应该变成一些字符串。 NSLog 报告方法被调用,但标签没有改变。这里有什么问题?

(注意:可能会有一些小错误,因为我现在没有所有代码,所以我不得不输入其中的一些)。

【问题讨论】:

  • 我想知道你为什么使用一个类来保存标签并更新它们?还想知道您是否将这些类中的标签添加到您的 UIViewControllers 视图中
  • 好吧,因为我认为某种用于处理更新的集中类是有意义的......但也许我不明白 Objective-C 编程应该如何工作。
  • 真的不需要,你可以直接在你的 UIViewCOntroller 中处理更新标签,这就是控制器用来管理你的视图的东西

标签: iphone class methods label


【解决方案1】:

这里是关于设计的一句话:

您似乎希望在两个或多个视图控制器实现之间共享某些功能。在这种情况下,您可能希望创建一个从 UIViewController 派生的通用基类,并从该类派生您的两个视图。 BaseView 将声明您可以在 IB 中连接的常见 UI 组件的出口。

@interface BaseUIViewController : UIViewController {
    IBOutlet UILabel *lbl1;
    IBOutlet UILabel *lbl2;
}

@property (nonatomic, retain) IBOutlet UILabel *lbl1;
@property (nonatomic, retain) IBOutlet UILabel *lbl2;

- (void)updateLabels;

@end

...

@interface ViewController1 : BaseUIViewController {
    IBOutlet UIButton *button1;

...

【讨论】:

    【解决方案2】:

    如果NSLog() 运行但标签没有更新,则几乎可以肯定lbl1lbl2 为零。它们几乎肯定为零,因为它们实际上并没有在 IB 中连接,或者您在 -viewDidLoad 运行之前运行此代码。在您的设计中,您必须避免使用-updateLabels,直到视图实际加载并连接其插座之后。视图会延迟加载,因此这些标签要到第一次显示视图之前才会创建。

    简短的版本是您可能应该在-viewDidLoad 中调用-updateLabels

    【讨论】:

    • 如果值发生变化应该如何处理?就像,在一个真实的程序中,someWord 字符串可能是一个不断变化的变量。这是设置一个经常更改标签文本的程序的坏方法吗?
    • 如果文本经常更改,那么您可能应该使用通知来使 UI 元素保持最新。应该有一个模型对象,其中包含您所代表的数据。当数据发生变化时,它应该发布通知。 ViewController 在可见时(并且仅在可见时)应该观察该通知并更新标签以匹配新值。您应该使用 -viewWillAppear/Disappear 订阅和取消订阅通知。 developer.apple.com/documentation/Cocoa/Conceptual/…robnapier.net/blog/thoughts-nsnotifications-42
    【解决方案3】:

    好的,这段代码有几个方面令人困惑,所以我将从您在对象和类之间做出的明显区别开始。

    目的是什么:

    NSObject *UpdateClassObject;
    

    这是什么?它是如何分配的(从笔尖?)?从名称上看,您似乎只是想要一个 UpdateClass 类的实例,其目的是:

    UpdateClass *updateClass;
    

    您似乎没有使用前者,所以我不确定它为什么会在那里。

    现在,解决问题的症结所在:您正在调用[updateClass updateLabels],而您的 NSLog 语句表明它确实被调用了。这告诉我,最有可能的问题是您的标签lbl1lbl2 实际上都是nil。请记住,在 Objective-C 中,向 nil 发送消息(如本例中的 updateText:)不会引发任何错误,它只会静默失败。

    那么为什么他们是零?好吧,它们被声明为IBOutlets,这让我觉得您有一个文件所有者为UpdateClass 的NIB 文件,它实际将一些UILabels 连接到您的成员变量。如果这是正确的,那么您需要使用 NIB 正确初始化 updateClass

    updateClass = [[UpdateClass alloc] initWithNibName:@"UpdateClass" bundle:nil]; // or whatever the nib is called
    

    但你实际上在做的是:

    updateClass = [[UpdateClass alloc] init];
    

    这意味着该类永远不会从 NIB 初始化,并且您的标签永远不会被连接。

    最后一点,在你的类名中使用“类”这个词是相当多余的——它显然是一个类。这也可能导致混淆 - 您存储 UpdateClass 实例的实例变量称为 updateClass - 对我来说,这意味着它实际上存储了类型为 Class 的对象的实例(您可以拨打[SomeClass class]获取)。

    【讨论】:

      【解决方案4】:

      您将 updateLabels 消息发送到错误的 UpdateClass。

      您说您在 InterfaceBuilder 中连接了一个 UpdateClass 实例,该实例也与 IB 中设置的标签有连接。因此,当您的视图被加载时,它已经从 NIB 注入了 UpdateClass 对象。

      在您的 viewDidLoad 实现中,您创建了一个新的 UpdateClass 实例。该实例没有设置标签(它们为零)。因此,一旦您将 updateLabels 方法发送给该对象,该对象就没有要更新的标签了。

      只要丢掉viewDidLoad中updateClass的声明和分配,将updateLabels消息发送给UpdateClassObject即可。考虑将成员 UpdateCLassObject 重命名为 updateClass 或者更好,将类重命名为 updater 之类的名称。也可以考虑使用基类。

      【讨论】:

        猜你喜欢
        • 2017-06-11
        • 2020-05-06
        • 2017-04-22
        • 2013-05-12
        • 2021-10-18
        • 1970-01-01
        • 1970-01-01
        • 2015-07-28
        • 1970-01-01
        相关资源
        最近更新 更多