当在另一个类中调用方法时,我想更改另一个对象的属性。
更改此对象的属性的代码位于第一个类的方法中,并且在从它自己的类调用它时起作用,但是当从另一个类调用时,该方法中的对象返回nil。
以下是代码:
ViewController.h
@interface ViewController : UIViewController {
UIView *menuView; //the object
}
@property (nonatomic, retain) IBOutlet UIView *menuView;
-(void)closeMenu; //the method
@end
ViewController.m
@implementation ViewController
@synthesize menuView;
-(void)closeMenu{
[menuView setFrame:CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)];
NSLog(@"%f", menuView.frame.size.height); //returns height when method is called from it's own class. But returns 0 (nil) when called from the other class.
}
SDNestedTableViewController.h (没什么太重要的,但可能有帮助?)
@interface SDMenuViewController : SDNestedTableViewController{
}
SDNestedTableViewController.m
#import "SDMenuViewController.h"
#import "ViewController.h"
- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{
ViewController *firstViewController = [[[ViewController alloc] init] autorelease];
SelectableCellState state = subItem.selectableCellState;
NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
switch (state) {
case Checked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);
[firstViewController closeMenu]; //called from other class
break;
case Unchecked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
break;
default:
break;
}
}
答案 0 :(得分:4)
您发布的内容如下:
-(void)closeMenu{
// menuView is never initialized, == nil
[nil setFrame:CGRectMake(0, -0, 0, 0)];
NSLog(@"%f", 0); //returns height when method is called from it's own class. But returns 0 (nil) when called from the other class.
}
所以你正在做NSLog(@"%f", 0);
。
如果您通过访问view
属性加载视图,则menuView将由IB规则初始化。
有关viewController视图加载/卸载的详细信息,请参阅reference docs。
答案 1 :(得分:2)
我认为这可能对你有所帮助。
在AppDelegate
课程中,您必须声明ViewController
课程的对象。将其设为YourAppDelegate
类的属性。如下。 (这将导入ViewController
类并创建YourAppDelegate
类的共享对象,以便您只需导入YourAppDelegate
即可全局访问YourAppDelegate.h
类的成员。
#import "ViewController.h"
#define UIAppDelegate ((YourAppDelegate *)[UIApplication sharedApplication].delegate)
@interface YourAppDelegate : NSObject <UIApplicationDelegate>
{
ViewController *objViewController;
}
@property (nonatomic, retain) ViewController *objViewController;
@end
并在YourAppDelegate.m
文件中合成属性。
@implementation YourAppDelegate
@synthesize objViewController;
@end
然后棘手的部分是,您必须在加载ViewController
类时在YourAppDelegate
类中备份ViewController
类的对象。
首先导入YourAppDelegate.h
类和ViewController.h
工具ViewController.m
代表中的viewWillAppear:
,如下所示。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIAppDelegate.objViewController = self;
}
然后在SDNestedTableViewController.m
,
#import "SDMenuViewController.h"
#import "ViewController.h"
- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{
ViewController *firstViewController = (ViewController *)UIAppDelegate.objViewController;
if(firstViewController && [firstViewController isKindOfClass:[ViewController class]])
{
SelectableCellState state = subItem.selectableCellState;
NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
switch (state) {
case Checked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);
[firstViewController closeMenu]; //called from other class
break;
case Unchecked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
break;
default:
break;
}
}
}
试试这种方式。我不是说这是正确的方法,但这应该有效。很高兴,如果这对你有所帮助。
答案 2 :(得分:1)
- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem {
ViewController *firstViewController = [[[ViewController alloc] init] autorelease];
...
[firstViewController closeMenu];
}
当您从那里调用closeMenu
时,它永远不会被初始化,因为没有足够的时间来初始化视图控制器的view
,viewDidLoad
的{{1}}方法是此时也未被调用。 {nib}也不会从nib创建firstViewController
,因此这就是menuView
的原因。
也许由于某种原因可能会有一段延迟,所以nil
被创建,但这不是你应该在iOS中做的事情。
因此,如果您不想展示自己的menuView
,只需在menuView
而不是firstViewController
中添加一些布尔值:
closeMenu
然后在firstViewController.shouldCloseMenu = YES;
ViewController
方法中执行以下操作:
viewDidLoad
也许这不是最好的方法,但现在你知道它是如何工作的。
答案 3 :(得分:1)
我相信你的问题与初始化viewController的方式有关。
而不是
ViewController *firstViewController = [[[ViewController alloc] init] autorelease];
使用
ViewController *firstViewController = [[[ViewController alloc] initWithNibName:@"yourNibName" bundle:nil] autorelease];
我假设你有一个笔尖因为你正在使用IBOutlet。但我相信IBOutlet永远不会被设置,因为你还没有加载nib文件。
同时仔细检查您的IBOutlet与界面构建器的连接并使用“self.menuView”
答案 4 :(得分:1)
编辑2:
嗯,您已将代码发送给我,所以现在我再也不能说我没有足够的信息来解决您的问题。
让我们看看。
现在我看到你的ViewController是你应用的rootViewController,如下所示:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
好,现在ViewController如何与您的SDNestedTableViewController相关联?
你在ViewController的viewDidLoad中有这个:
- (void)viewDidLoad
{
[super viewDidLoad];
SDMenuViewController *mvc = [[[SDMenuViewController alloc] initWithNibName:@"SDNestedTableView" bundle:nil] autorelease];
[self addChildViewController:mvc];
[mvc didMoveToParentViewController:self];
[menuView addSubview:mvc.view];
// Some other stuff with gesture recognizers I'm omitting...
[self openMenu];
}
好吧,所以看起来SDMenuViewController是ViewController的子代。现在,您在SDMenuViewController中有一个名为item的方法:subItemDidChange:
- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{
ViewController *firstViewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];
SelectableCellState state = subItem.selectableCellState;
NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
switch (state) {
case Checked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);
//close the menuView
[firstViewController closeMenu];
break;
case Unchecked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
break;
default:
break;
}
}
所以,你想要引用回到现有的 ViewController对象,对吗?因为那里你正在制作另一个。所以,你可以这样做:
ViewController *firstViewController = self.parentViewController;
这将引导您对SDMenuViewController的父级进行引用,该父级是ViewController的实例。当您进行addChildViewController:
来电时,会设置此属性。
好吧,但这很令人困惑:
在你的帖子中,你说你的item:subItemDidChange:
方法在SDNestedTableViewController中,但在你发给我的代码中它是在SDMenuViewController中。
在SDNestedTableViewController中,我找到了这个方法:
- (void) mainItem:(SDGroupCell *)item subItemDidChange: (SDSelectableCell *)subItem forTap:(BOOL)tapped
{
if(delegate != nil && [delegate respondsToSelector:@selector(item:subItemDidChange:)] )
{
[delegate performSelector:@selector(item:subItemDidChange:) withObject:item withObject:subItem];
}
}
所以看起来你没有使用与原帖相同的代码,但足够接近,无论如何。
现在,如果你想在应用程序中从任何地方获得对ViewController实例的引用,不仅仅是你的SDMenuViewController(恰好是ViewController实例的子代),你应该使用@Mathew Varghese的answer。
以下是对此方法的重述:
+ (AppDelegate *)instance;
添加到AppDelegate.h文件中。像这样:
+ (AppDelegate *)instance
{
AppDelegate *dg = [UIApplication sharedApplication].delegate;
return dg;
}
然后,在您想要该引用的任何对象中,您#import AppDelegate.h
并说ViewController *vc = AppDelegate.instance.firstViewController;
无论如何,这只是另一种说法Mathew之前提到过的方式。
答案 5 :(得分:0)
我建议您按以下步骤解决此问题。
请勿在{{1}}中使用firstViewController
的任何实例或变量。
在案例检查栏中,将讯息发布到SDMenuViewController
在NSNotificationCenter
注册具有相同消息ID的消息时,请使用ViewController
方法作为其处理程序。
对我来说,使用消息中心调度处理可以解耦控制器之间的关系。这是一种更好的方式,您可以更少地关注另一个控制器的生命周期。
希望它会有所帮助。
答案 6 :(得分:0)
ViewController alloc-init
和视图控制器属性alloc-init
之间存在差异。
关于你的第二个例子(从另一个类调用)。您当前的代码表明您alloc-init
firstViewController,但随后不对其执行任何操作。假设您没有覆盖ViewController的init
方法,其属性和iVars应该是nil
(或者在最坏的情况下未定义)。您需要先alloc-init
firstViewController.menuView
firstViewController.menuView = [[UIView alloc] initWithFrame]; // Don't do this.
。即:
viewDidLoad
这种方法的问题在于你将firstViewController的属性设置为另一个类,这通常是相当平均的设计实践。这个必需的设置通常会在closeMenu
中进行,但是因为你还没有对firstViewController做任何事情,所以它永远不会被调用。
相比之下,当您从自己的View Controller中调用menuView = [[UIView alloc] init];
时,您实际上正在使用视图执行某些操作并且首先调用viewDidLoad(或找到{{1}}的任何地方),因此初始化你的menuView对象。
在尝试对其执行任何操作之前,您需要确保首先初始化menuView对象,只需初始化包含它的View Controller是不够的。
答案 7 :(得分:0)
#import "SDMenuViewController.h"
#import "ViewController.h"
- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{
//为什么我们在这里分配这个对象,如果仅在Checked:
的情况下需要它
ViewController *firstViewController = [[[ViewController alloc] init] autorelease];
SelectableCellState state = subItem.selectableCellState;
NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
switch (state) {
case Checked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);
[firstViewController closeMenu]; //called from other class
break;
case Unchecked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
break;
default:
break;
}
}
将其更改为
#import "SDMenuViewController.h"
#import "ViewController.h"
- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{
//为什么我们在这里分配这个对象,如果仅在Checked:
的情况下需要它
SelectableCellState state = subItem.selectableCellState;
NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
switch (state) {
case Checked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);
// here no need to put object in autorelease mode.
ViewController *firstViewController = [[ViewController alloc] init];
[firstViewController closeMenu]; //called from other class
[firstViewController release];
break;
case Unchecked:
NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
break;
default:
break;
}
}
答案 8 :(得分:0)
一切正确,更改 - (void)closeMenu 方法,如...
-(void)closeMenu
{
menuView=[[UIView alloc]initWithFrame:CGRectMake(50.0,50.0,200.0,200.0)]
NSLog(@"%f", menuView.frame.size.height); //returns height when method is called from it's own class. But returns 0 (nil) when called from the other class.
}
试试这个并告诉我。
答案 9 :(得分:0)
尝试删除 UIView * menuView; //来自界面文件的对象
@interface ViewController : UIViewController {
// try to remove this line
UIView *menuView; //the object
}
并更新此方法
-(void)closeMenu{
[self.menuView setFrame:CGRectMake(self.menuView.frame.origin.x, -self.menuView.frame.size.height, self.menuView.frame.size.width, self.menuView.frame.size.height)];
NSLog(@"%f", self.menuView.frame.size.height);
}
答案 10 :(得分:0)
我建议你用这个:
if(menuView) {
[menuView setFrame:CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)];
} else {
NSLog(@"menuView is nil");
}