作为Objective-C编码的新手,我开始编写一个基本应用程序,完全以编程方式(不使用storyboard或xib)编写一个文件,AppViewController
h和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
使用标记设置新视图(以便稍后我可以使用我的新类引用它) 然后从我的新类中执行一个方法来填充我的新视图。
Picker.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
设置我的变量和可访问的方法。
Picker.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系统有关,但是我发现的所有响应都没有与我上面的设置类型相关或使用。我确定它非常简单,但经过几天的搜索失败后,它正式让我疯狂。
答案 0 :(得分:0)
问题很可能是Picker
中正在创建的UIPickerViewController
实例从未添加到视图层次结构中,因此过早发布(前提是我们正在讨论使用ARC的项目这里)。
这导致pickerview的委托和数据源变得无效,并且基本上指向任何随机对象。这就是导致崩溃的原因:无法传递给您的代理人的消息,因为委托已经死了。拾取器仍然保留一个指针,该指针用于指向委托,但它已变为无效并且现在指向一个随机对象,在这种情况下是一个表视图单元格,它基本上不知道如何处理此消息并崩溃。
如果将Picker * picker作为ivar或者保留/强属性添加到UIPickerViewController.h,问题应该消失 - 这将使选择器保留在viewDidLoad
方法的范围之外并且应该保持活动状态。
但这只是一种解决方法,真正的问题是你的整体设计。你说你是objective-c的新手,事实上,你似乎缺乏对iOS视图和视图控制器层次结构的基本理解,并且在某种程度上缺乏面向对象编程的概念。在尝试修复代码之前,您可能想要深入研究一些更基本的东西,因为坦率地说,它应该是重写而不是修复。
我很乐意为您提供有关如何构建代码的建议,但请提供一些有关您希望首先实现哪些功能的信息。
修改(回复您的评论):
根据经验,除非必要,否则不要在多个类上传播功能。对于服务于相当基础设施目的的对象,比如专门的文本字段或挑选视图,总是问自己:“如果我想在另一个项目中重用该对象,那么就像使用任何其他现有对象一样容易,例如,例如,UILabel?“如果答案是“否”,则出现问题。理想情况下,接口对象是自包含的并且要使用它们,您只需调用它们,将它们添加到视图中并告诉它们,要显示哪个文本或提供哪些选项。如果该信息可能会发生变化,或者该对象需要与代码的其他部分进行交互,请使用委托和协议。在任何情况下,您的对象的功能都不应与硬编码值相关联,或者依赖于某些视图以获得某个标记。
如果您是UIView的子类,则生成的对象应该像任何其他UIView实例一样。它应该由您或某个对象添加到视图层次结构中,但不应添加或删除自身。如果它在没有被添加到视图层次结构中的情况下工作,那就出错了。一个视图的目的是成为你的界面的一部分,它所包含的所有逻辑应该为此而努力,而不是更多,而不是更少。
通常,界面对象不应互相干扰。如果某个对象发生了某些事情(按下按钮,选择了选项,文本已更改......)而另一个对象应该反映出该更改,那么视图控制器有责任实现这一目标。视图控制器是逻辑发生的地方。如果存在需要大量复杂逻辑的任务,那么将该逻辑封装到目标构建类中可能是个好主意。一个这样的例子是管理网络连接的类。此类应该是自包含的:如果视图控制器需要一些远程信息,它会询问您的网络类。一旦您的网络类具有该信息(或无法检索它),它就会向您的视图控制器报告。视图控制器然后更新接口 - 在任何情况下网络类都不应包含影响接口的代码。
重要的是要了解您可以很好地忽略这些规则并最终得到一个有效的应用程序。在某些情况下,“直接”方式似乎更容易实现,因此可能看起来很诱人。但是一旦你开始调试你的代码,你就会付出代价。如果你的选择器没有按照它应该的方式运行,你需要查看几个地方并围绕几个对象,只是为了使一个接口对象表现正确。可能你会在修复另一个功能时破坏一个功能。
因此,尽管需要更多的计划和学习,但要从一开始就尽量做到正确。相信我,它付出了代价,我几年前就像你一样开始了;)