我有4个ivars:
UIView *view1;
UIView *view2;
UIView *view3;
UIView *view4;
我希望能够以动态的方式alloc
和init
,而不是:
view1 = [[MyView1 alloc] initWithFrame:....
view3 = [[MyView2 alloc] initWithFrame:....
view4 = [[MyView3 alloc] initWithFrame:....
view4 = [[MyView4 alloc] initWithFrame:....
所以,我尝试使用数组并将这些ivars的名称存储在其中:
[array addObject:@"view1"];
[array addObject:@"view2"];
[array addObject:@"view3"];
[array addObject:@"view4"];
所以在循环中我会这样做:
[self valueForKey:[array objectAtIndex:x]] = [[[[self valueForKey:[array objectAtIndex:x]] class] alloc] initWithFrame:(CGRect){.....
以上产生错误:
表达式不可分配。
希望有人能告诉我为什么上述情况无法完成。
我的问题是:
我觉得这不是一种聪明的做事方式。
现在我只有4个观点,但是谁知道将来我可能会有更多观看次数。
所以,我的想法是,我想找到一种更有活力的方法来实现这一目标,而不是硬编码。
我的想法是,在编译时,所有这些视图都只是UIViews
。
直到运行时才能将这些视图解析为各个类类型
(即MyView1
,MyView2
等等)以及alloc
和init
他们并指定他们
相应于我班上的ivars(即view1
,view2
,view3
等。
我使用数组的原因是,如果将来我添加了另一个名为view5
的类MyView5
的视图,我可以循环alloc
和{{1}使用init
进行处理。如果这种方式仍然不是最佳的,请纠正我。
总而言之,我想以一种只在编译时才知道这些对象只是类型[array count]
的方式来设置我的控制器。只有在运行时才能将它们单独解析为UIView
,MyView1
(MyView2
的子类)等,并将它们分配给我的控制器中的ivars(同样,它们被命名为{{1 ,},UIView
等)。
如果我将来添加另一个视图,我就不必在这个控制器中查看所有地方并进行硬编码:view1
有人能告诉我如何以最佳方式(未来)和动态地完成这项工作吗?
修改 的
我刚刚想到:如果我只能在运行时创建这些ivars会更好,以便将来可以动态创建所有东西。
答案 0 :(得分:2)
如果我理解您的要求,请允许我提供您可能喜欢的其他方法:
// Set up a mutable array of objects
NSMutableArray *views = [[NSMutableArray alloc] init];
// Set up an array of strings representing the classes - you can add more
// later, or use -stringWithFormat: to make the class names variable
NSArray *classes = @[@"MyView1", @"MyView2", @"MyView3", @"MyView4"];
// Now loop through it and instantiate one of each kind
for (NSString *className in classes)
[views addObject:[[NSClassFromString(className) alloc] initWithFrame:CGRectZero]];
请注意谨慎使用NSClassFromString
,因为您可能会意外地将-initWithFrame:
消息发送到未实现该消息的类型。
希望这有帮助!
编辑:我看到我已经给你一个过于实现的答案,而你似乎在寻找程序设计方面。
当你设计你的控制器课程时,你考虑将来如何使用这门课程是件好事。也就是说,你需要对你想要这个类的抽象有一个特定的想法。换句话说,不要试图让控制器类完全解耦,因为在某些时候你的类将是大量无用的管理代码。
那么你如何编写一个同时解耦和功能的类呢?我建议您在Apple的课程中查找示例。以下是一些:
UIViewController ,可能是iOS上最重要,最通用的课程。他们将其设计为易于子类化,但也有许多预制的子类,如导航控制器和表视图控制器品种。
UIDocument ,您需要的所有文档模型对象的模板。系统实现处理iCloud同步,文件管理等的所有细节,同时不了解文档内容本身。但是,用户子类在NSData对象中提供必要的信息。
UIGestureRecognizer ,基于触摸的UI的基础。大多数人只使用系统提供的tap / swipe / pinch子类,但抽象超类本身(无论是否是子类)检测到你想要的任何手势并发送必要的消息。同样,手势识别器不知道您将它附加到哪个视图,但它仍然可以执行其工作。
你看到我在这里得到了什么吗? Apple的课程表明,有些方法可以提供必要的功能,同时保持抽象,但不需要进入运行时杂技。正如其中一位评论者建议的那样,您真正需要的只是一组视图对象。您可以让客户端对象执行此操作,而不是让您的控制器类实例化视图。这一切都是为了在抽象和功能之间找到平衡。
答案 1 :(得分:1)
问题是,你正在考虑这个问题,好像你对数组元素的调用会在编译之前替换你的代码(就像宏一样)。它只是不起作用。例如:
[self valueForKey:[array objectAtIndex:x]] = ...
编译器将[self valueForKey:[array objectAtIndex:x]]
视为值,并且“认为”嘿,你不能为某个值提供帮助。
尝试以下内容(我已将其拆分为多个语句以提高可读性,并使代码更加不言自明):
string className = [array objectAtIndex:x];
Class classToInit = NSClassFromString(className);
UIView *viewToInit = [[classToInit alloc] initWithFrame:...];
[self setValue:viewToInit forKey:className];
请注意,使用此方法,属性名称(和顺便说一下,它们也必须是属于非KARC才能工作的属性)必须与您的类名匹配,即如果您的类名为{ {1}}您的财产也必须被称为MyView1
。您可能不希望这样(事实上根据您在文中的说明,您没有)。因此,为了使其工作,您可以创建一个字典,将您的属性名称映射到您的类名,并枚举它的键:
MyView1