0

作为 Objective-C 编码的新手,我开始编写一个基本的应用程序,完全以编程方式(不使用故事板或 xib)在一个文件中,即我的AppViewControllerh 和 m 文件。一切都很可爱。

所以我想通过子类化部分来分解大量代码,除了 UIPickerView 之外,一切都很好。事实上,简单地评论[background addSubview:colorPicker];似乎完全解决了这个问题。我从来没有在网上找到答案,所以我开始制作一个新文件来复制上述问题。所以这里是:

UIPickerViewController.h


#import <UIKit/UIKit.h>
#import "Picker.h"
@interface UIPickerViewController : UIViewController
@end

只需导入我的新课程。

UIPickerViewController.m

#import "UIPickerViewController.h"
@interface UIPickerViewController ()
@end

@implementation UIPickerViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    UIView *superview = self.view;
    int height = superview.bounds.size.height;
    int width = superview.bounds.size.width;
    CGRect popupRect = CGRectMake(0, 0, width, height);
    UIView *popup = [[UIView alloc]initWithFrame:popupRect];
    popup.tag = 8;
    [superview addSubview:popup];
    Picker *picker = [[Picker alloc]initWithFrame:popupRect];
    [picker viewAddTypeScreenToView:superview];
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
} 
@end

设置一个带有标签的新视图(以便我以后可以用我的新类引用它)然后从我的新类中操作一个方法来填充我的新视图。

选择器.h


#import <UIKit/UIKit.h>

@interface Picker : UIView
<UIPickerViewDataSource,UIPickerViewDelegate>
{
    UIPickerView *colorPicker;
    NSMutableArray *colorsArray;
}

@property (nonatomic, retain) UIPickerView *colorPicker;
@property (nonatomic, retain) NSMutableArray *colorsArray;
@property (strong,nonatomic) UILabel *myValue;

-(void)viewAddTypeScreenToView:(UIView*)superview;

@end

设置我的变量和可访问的方法。

选择器.m


#import "Picker.h"

@implementation Picker

@synthesize colorsArray;
@synthesize colorPicker;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
    }
    return self;
}


-(void)viewAddTypeScreenToView:(UIView*)superview
{
    UIView *baseView =[superview viewWithTag:8];

    int height = baseView.bounds.size.height;
    int width = baseView.bounds.size.width;

    CGRect fullScreen = CGRectMake(0, 0, width, height);
    UIView *background = [[UIView alloc]initWithFrame:fullScreen];
    background.backgroundColor = [UIColor blackColor];

    colorsArray = [[NSMutableArray alloc] initWithObjects:@"Red",@"Blue",@"Yellow",@"Green",nil];

    CGRect myPickerRect = CGRectMake(10, 70, (width/2)-40, 200);
    colorPicker = [[UIPickerView alloc]initWithFrame:myPickerRect];
    colorPicker.dataSource = self;
    colorPicker.delegate = self;
    colorPicker.showsSelectionIndicator = YES;
    [colorPicker selectRow:2 inComponent:0 animated:YES];

    CGRect labelFrame = CGRectMake(10, 10, 180, 50);
    _myValue = [[UILabel alloc]initWithFrame:labelFrame];
    _myValue.textColor = [UIColor redColor];
    _myValue.text = @"select colour";
    [background addSubview:_myValue];
    [background addSubview:colorPicker];
    [baseView addSubview:background];

}



-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 1;
}

-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    return colorsArray.count;;
}

-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    return colorsArray[row];
}

-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    _myValue.text = [NSString stringWithString:colorsArray[row]];
}

@end

最后是picker类文件中的方法调用的初始化。这给了我一个错误

-[UITableViewCellContentView pickerView:titleForRow:forComponent:]: unrecognized selector sent to instance 0x8f2b000
2014-03-19 10:29:48.407 Briefcase[1800:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITableViewCellContentView pickerView:titleForRow:forComponent:]: unrecognized selector sent to instance 0x8f2b000'

我读过的内容与数据源或 ARC 系统有关,但是我发现的任何响应都与我上面的设置类型无关或使用。我敢肯定这很简单,但经过几天的搜索失败后,它正式让我发疯了。

4

1 回答 1

0

问题很可能Picker是正在创建的实例UIPickerViewController从未添加到视图层次结构中,因此过早释放(假设我们在这里谈论的是使用 ARC 的项目)。

这导致pickerview的委托和数据源变得无效,并且基本上指向任何随机对象。这就是导致您崩溃的原因:无法传递给您的代表的消息,因为代表已经死了。选择器仍然保留一个指针,该指针曾经指向委托,但现在已变为无效并指向一个随机对象,在本例中是一个表格视图单元格,它基本上不知道如何处理此消息并崩溃。

如果您将 Picker *picker 作为 ivar 或保留 / 强属性添加到 UIPickerViewController.h,问题应该会消失 - 这会将选择器保留在viewDidLoad方法范围之外并且应该使其保持活动状态。

但这只是一种解决方法,真正的问题是您的整体设计。您说您是 Objective-c 的新手,实际上,您似乎缺乏对 iOS 视图和视图控制器层次结构的基本了解,在某种程度上,还缺乏面向对象编程的概念。在尝试修复代码之前,您可能想深入研究一些更基本的东西,因为坦率地说,它应该被重写而不是修复。

我很乐意为您提供有关如何构建代码的建议,但请提供一些您希望首先实现的功能的信息。

编辑(回应您的评论):

  • 根据经验,除非必要,否则不要将功能分散到多个类中。对于服务于基础设施目的的对象,例如专门的文本字段或选择器视图,请始终问自己:“如果我想在另一个项目中重用该对象,那是否像使用任何其他现有对象一样容易,例如,例如,UILabel?” 如果答案是“否”,那么就有问题了。理想情况下,界面对象是自包含的,要使用它们,您只需调用它们,将它们添加到视图中并告诉它们要显示哪些文本或提供哪些选项。如果该信息可能会更改,或者如果对象需要与代码的其他部分交互,请使用委托和协议。

  • 如果您将 UIView 子类化,则生成的对象的行为应该与任何其他 UIView 实例一样。它应该由您或某个对象添加到视图层次结构中,但不应添加或删除自身。如果它完全没有被添加到视图层次结构中就可以工作,那么就有问题了。视图的目的是成为界面的一部分,并且它包含的所有逻辑都应该为此工作,而不是更多,而不是更少。

  • 通常,接口对象不应相互干扰。如果某个对象发生了某些事情(按下按钮、选择了选项、更改了文本……)并且另一个对象应该反映该更改,则视图控制器有责任实现这一点。视图控制器是逻辑发生的地方。如果有一个任务需要很多复杂的逻辑,那么将这个逻辑封装到一个目的构建类中可能是一个好主意。一个这样的例子是管理网络连接的类。这个类应该是自包含的:如果视图控制器需要一些远程信息,它会询问你的网络类。一旦您的网络类拥有该信息(或未能检索到该信息),它就会向您的视图控制器报告。

重要的是要了解,您很可能忽略这些规则,最终仍然可以使用正常的应用程序。在某些情况下,“直接”方式可能看起来更容易实现,因此看起来非常诱人。但是你会在以后付出代价——一旦你开始调试你的代码。如果您的选择器没有按应有的方式运行,您需要查看几个地方并围绕几个对象考虑,只是为了使一个界面对象表现正确。并且您可能会在修复另一个功能时破坏一个功能。

所以,试着从一开始就做好,即使它需要更多的计划和学习。相信我,这是有回报的,几年前我和你一样开始了;)

于 2014-03-19T13:38:38.077 回答