0

我正在尝试创建一个从 api 中提取 json 的应用程序,其中包含一组关于界面外观的说明。所以基本上 json 将包含一个 NSDictionary 数组,每个 NSDictionary 将是一个显示在屏幕上的对象。

在 NSDictionary 中将包含对象如何显示的所有详细信息,例如对象的类型、对象的位置和对象的大小。

我编写了代码来接受屏幕上的一系列按钮。

for (int i = 0; i < self.jsonObjects.count; i++) {
    NSDictionary *jsonObject = [self.jsonObjects objectAtIndex:i];
    if ([[jsonObject objectForKey:@"object"] isEqualToString:@"UIButton"]) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];

        NSNumber *x = [jsonObject objectForKey:@"xlocation"];
        NSNumber *y = [jsonObject objectForKey:@"ylocation"];
        NSNumber *width = [jsonObject objectForKey:@"width"];
        NSNumber *height = [jsonObject objectForKey:@"height"];
        NSString *title = [jsonObject objectForKey:@"title"];
        [button setFrame:CGRectMake(x.intValue, y.intValue, width.intValue, height.intValue)];
        [button setTitle:title forState:UIControlStateNormal];
        [self.view addSubview:button];
    }
}

现在我可以为每个对象拥有大量的 if 语句,并让程序做同样的事情,但我试图避免它。

基本上我要问的是实现这一点以最小化编码和提高代码可读性的最佳方法是什么。

这是我为模拟按钮的 json 输出而编写的代码。

NSDictionary *button = [[NSDictionary alloc] initWithObjectsAndKeys:@"UIButton", @"object",@"PressMe",@"title",@"10",@"xlocation",@"10",@"ylocation",@"100",@"width",@"100",@"height", nil];

NSDictionary *button2 = [[NSDictionary alloc] initWithObjectsAndKeys:@"UIButton", @"object",@"Dont Press",@"title",@"10",@"xlocation",@"210",@"ylocation",@"100",@"width",@"100",@"height", nil];

self.jsonObjects = [[NSArray alloc] initWithObjects:button,button2, nil];

由于我仍然必须创建 api,因此 json 输出可以非常灵活。

我正在考虑拥有一系列数组。其中数组中的每个数组都是按钮数组或文本字段数组。那么我只需要大约 20-30 个数组来覆盖不同的对象类型,并且可以遍历主数组,然后遍历每个按钮或文本字段的数组。

为伊莱·加内姆

object  UIView *    0x07145c60
UIResponder UIResponder 
_layer  CALayer *   0x07145e80
_tapInfo    id  0x00000000
_gestureInfo    id  0x00000000
_gestureRecognizers NSMutableArray *    0x00000000
_subviewCache   NSArray *   0x075213e0
_charge float   0
_tag    NSInteger   0
_viewDelegate   UIViewController *  0x00000000
_backgroundColorSystemColorName NSString *  0x00000000
_viewFlags  <anonymous struct>
4

4 回答 4

0

You could always use a framework to do the fetching/parsing, see this post.

Also, you could use the objective-c run-time if you'd prefer a more bespoke approach. I wrote a dynamic mapper for a recent project.

For example, you could sub-class UIButton, have an initWithDictionary: method that parses the json collection per button - and because you say you have great control over the web service, you could also combine the size and origin fields into a string representing the rect "{x,y,width,height}", and inside your initWithDictionary field, for the given 'frame' key, convert the string to a rect with CGRectFromString()

于 2013-04-09T12:17:54.400 回答
0

我建议封装代码:

    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    NSNumber *x = [jsonObject objectForKey:@"xlocation"];
    NSNumber *y = [jsonObject objectForKey:@"ylocation"];
    NSNumber *width = [jsonObject objectForKey:@"width"];
    NSNumber *height = [jsonObject objectForKey:@"height"];
    NSString *title = [jsonObject objectForKey:@"title"];
    [button setFrame:CGRectMake(x.intValue, y.intValue, width.intValue, height.intValue)];
    [button setTitle:title forState:UIControlStateNormal];

在具有以下签名的工厂方法中:

- (UIButton*)butttonFromJSONDescription:(NSDictionary*)jsonObject;

那么你的循环会变成:

if ([[jsonObject objectForKey:@"object"] isEqualToString:@"UIButton"]) {
    [self.view addSubview:[self buttonFromJSONDescription:jsonObject]];
} else if ([[jsonObject objectForKey:@"object"] isEqualToString:@"UITextField"]) {
    [self.view addSubview:[self textFieldFromJSONDescription:jsonObject]];
}

我了解您想要管理的对象类具有您可能希望在 JSON 中设置的不同属性。这似乎阻止了进一步的抽象。

于 2013-04-09T12:10:34.077 回答
0

您不应该创建数组数组,或者有 30 个 if 条件。您应该根据“对象”的值通过反射创建一个对象。像这样的东西:

id object = [[NSClassFromString(jsonObject[@"object"]) alloc] init];

如果你只发送 UIView 的子类作为你的“对象”,那么你可以这样写:

UIView *object = (UIView*)[[NSClassFromString(jsonOnject[@"object"]) alloc] init];
NSNumber *x = [jsonObject objectForKey:@"xlocation"];
NSNumber *y = [jsonObject objectForKey:@"ylocation"];
NSNumber *width = [jsonObject objectForKey:@"width"];
NSNumber *height = [jsonObject objectForKey:@"height"];
[object setFrame:CGRectMake(x.intValue, y.intValue, width.intValue, height.intValue)];

先写这个,看看它是如何工作的:

UIView *myView = (UIView*)[[NSClassFromString(@"UISwitch") alloc] init];
myView.frame = CGRectMake(0,0,100,40);
[self.view addSubview:myView];

为了改变对象的属性,遍历你的字典并执行必要的选择器。这里有一个例子来说明:

NSDictionary *jsonObject = @{@"setBackgroundColor:":[UIColor redColor]};
for (NSString *key in jsonObject)
{
    if ([myView respondsToSelector:NSSelectorFromString(key)])
    {
        [myView performSelector:NSSelectorFromString(key) withObject:jsonObject[key]];
    }
}
于 2013-04-09T12:11:01.957 回答
0

我刚刚实现了类似于您在我一直在开发的应用程序中所做的事情。我所做的是有一个类型的 json 语句,然后是一个项目数组。调用这些对象SectionItems,这样您将拥有一个完整的 json 数组SectionItems,您可以将其从 json 文件读入NSArray. 然后我所做的是为可能存在的每种类型SectionItems创建一个自定义UITableViewCell。创建一个UITableDataSource将检查您从 json 文件中读取indexPath.row的数组的数组,该数组将使用 中的项目构造适当的以显示在该行。SectionItemsUITableViewCellSectionItems

所以为了清楚起见,这就是我的SectionItems样子:

@interface SectionItem : NSObject

@property (strong) NSString *type; //controls what type of cell will be made in the datasource
@property (strong) NSString *data; //auxiliary data
@property (strong) NSArray  *items; //actual data to populate the cell with

-(id) initWithJSON:(NSDictionary *)jsonData;

@end

希望这可以帮助。我发现这种方式很有用,因为如果 json 中的数据发生变化,一切正常。json 的形成方式完全控制了如何查看数据。

于 2013-04-09T12:12:49.143 回答