Форум программистов, компьютерный форум CyberForum.ru

Objective-C

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 25, средняя оценка - 4.64
noname_club
102 / 90 / 9
Регистрация: 01.05.2013
Сообщений: 583
#1

Быстрое обращение к данным многомерных словарей - Objective-C

15.06.2013, 11:24. Просмотров 3144. Ответов 39
Метки нет (Все метки)

предлагаю на рассмотрение следующий метод работы с данными многомерных словарей

рассматриваются словари, чья многомерная структура состоит из словарей и массивов

1) сокращенные методы получения данных из словарей и массивов
Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// DKeyClass test version
 
#import <Foundation/Foundation.h>
 
@interface NSDictionary (NSDictionaryDkey)
 
-(id) key: (id) key;
 
@end
 
@interface NSArray(NSArrayDkey)
 
-(id) index: (int) index;
 
@end
данные методы зеркально отражают стандартные objectForKey: и objectAtIndex:

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// DKeyClass test version
 
#import "DkeyClass.h"
 
@implementation NSDictionary(NSDictionaryDkey)
 
-(id)key:(id)key {
    return  [self objectForKey:key];
}
@end
 
@implementation NSArray(NSArrayDkey)
 
-(id)index:(int)index {
    if (index>=self.count || index<0) {
        NSLog(@"DkeyClass ARRAY ERROR index at %d (max=%d) \n %@",index,self.count-1,self);
        return nil;
    }
    return [self objectAtIndex:index];
}
@end
дополнительно в метод index: добавлен логический блок проверки индекса, который не допускает внезапного завершения приложения из-за неверного индекса

2) примеры кода, показывающие удобство использования сокращенных конструкций key-index
Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// уровень 1
 
[_dict1 objectForKey:@"s1"];
 
[_dict1 key:@"s1"];
 
// уровень 2
 
[[_dict1 objectForKey:@"k1"] objectAtIndex:1];
 
[[_dict1 key:@"k1"] index:1];
 
// уровень 3
 
[[[_dict1 objectForKey:@"k1"] objectAtIndex:0] objectForKey:@"s3"];
 
[[[_dict1 key:@"k1"] index:0] key:@"s3"];
 
// уровень 4
 
[[[[_dict1 objectForKey:@"k1"] objectAtIndex:0] objectForKey:@"k3"] objectForKey:@"s4"];
 
[[[[_dict1 key:@"k1"] index:0] key:@"k3"] key:@"s4"];
3) тестовая программа

Быстрое обращение к данным многомерных словарей

состоит из кнопок на которые назначены действия показа данных через NSLog

в программе заполняется многомерный словарь состоящий из 4 уровней

1 - словарь
2 - массив
3 - словарь
4 - словарь

структура

Быстрое обращение к данным многомерных словарей

исходный код программы

ViewController.h
Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//
//  ViewController.h
//  test_dict4
//
//  Created by Mac on 6/15/13.
//  Copyright (c) 2013 Mac. All rights reserved.
//
 
#import <UIKit/UIKit.h>
#import "DkeyClass.h"
 
@interface ViewController : UIViewController<UIAlertViewDelegate>
- (IBAction)b1:(id)sender;
- (IBAction)b2:(id)sender;
- (IBAction)b3:(id)sender;
- (IBAction)b4:(id)sender;
- (IBAction)indexerror:(id)sender;
 
- (IBAction)obj1:(id)sender;
- (IBAction)obj2:(id)sender;
- (IBAction)obj3:(id)sender;
- (IBAction)obj4:(id)sender;
- (IBAction)indexobjError:(id)sender;
 
@property NSMutableDictionary* dict1;
 
@end
ViewController.m
Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//
//  ViewController.m
//  test_dict4
//
//  Created by Mac on 6/15/13.
//  Copyright (c) 2013 Mac. All rights reserved.
//
 
#import "ViewController.h"
 
@interface ViewController ()
 
@end
 
@implementation ViewController
 
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _dict1 = [NSMutableDictionary new];
    NSMutableArray * a2 = [NSMutableArray new];
    NSMutableDictionary * d3 = [NSMutableDictionary new];
    NSMutableDictionary * d4 = [NSMutableDictionary new];
    
    
    // дерево словарей заполнено
    [_dict1 setObject:a2 forKey:@"k1"];
    [a2 addObject:d3];
    [d3 setObject:d4 forKey:@"k3"];
    
    // заполняем словари строковыми данными
    
    [_dict1 setObject:@"level1" forKey:@"s1"];
    [a2 addObject:@"level2 array"];
    [d3 setObject:@"level3" forKey:@"s3"];
    [d4 setObject:@"level4" forKey:@"s4"];
 
    
    NSLog(@"текущая структура словарей %@",_dict1);
}
 
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
 
#pragma mark черезКлючи
 
- (IBAction)b1:(id)sender {
    id obj = [_dict1 key:@"s1"];
   
    NSLog(@"KEY МЕТОД строка уровень 1 \n%@", obj);
}
 
- (IBAction)b2:(id)sender {
    id obj = [[_dict1 key:@"k1"] index:1];
    
    NSLog(@"KEY МЕТОД строка уровень 2 \n%@", obj);
}
 
- (IBAction)b3:(id)sender {
    id obj = [[[_dict1 key:@"k1"] index:0] key:@"s3"];
    
    NSLog(@"KEY МЕТОД строка уровень 3 \n%@", obj);
}
 
- (IBAction)b4:(id)sender {
    id obj = [[[[_dict1 key:@"k1"] index:0] key:@"k3"] key:@"s4"];
    
    NSLog(@"KEY МЕТОД строка уровень 4 \n%@", obj);
}
 
- (IBAction)indexerror:(id)sender {
    // запрашиваем ошибочный индекс
    [[_dict1 key:@"k1"] index:2];
    
}
 
#pragma mark стандартный метод
 
- (IBAction)obj1:(id)sender {
    id obj = [_dict1 objectForKey:@"s1"];
    
    NSLog(@"СТАНДАРТНО строка уровень 1 \n%@", obj);
}
 
- (IBAction)obj2:(id)sender {
    id obj = [[_dict1 objectForKey:@"k1"] objectAtIndex:1];
    
    NSLog(@"СТАНДАРТНО строка уровень 2 \n%@", obj);
}
 
- (IBAction)obj3:(id)sender {
    id obj = [[[_dict1 objectForKey:@"k1"] objectAtIndex:0] objectForKey:@"s3"];
    
    NSLog(@"СТАНДАРТНО строка уровень 3 \n%@", obj);
}
 
- (IBAction)obj4:(id)sender {
    id obj = [[[[_dict1 objectForKey:@"k1"] objectAtIndex:0] objectForKey:@"k3"] objectForKey:@"s4"];
    
    NSLog(@"СТАНДАРТНО строка уровень 4 \n%@", obj);
}
 
- (IBAction)indexobjError:(id)sender {
    UIAlertView *a = [[UIAlertView alloc] initWithTitle:nil message:@"приложение сейчас прекратит работу из-за неверного индекса массива" delegate:self cancelButtonTitle:@"ok" otherButtonTitles: nil];
    [a show];
    
}
 
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
   // запрашиваем ошибочный индекс
   [[_dict1 objectForKey:@"k1"] objectAtIndex:2];
}
 
@end
лог после запуска программы

Bash
1
2
3
4
5
6
7
8
9
10
11
12
2013-06-15 09:46:43.865 test_dict4[709:c07] текущая структура словарей {
    k1 =     (
                {
            k3 =             {
                s4 = level4;
            };
            s3 = level3;
        },
        "level2 array"
    );
    s1 = level1;
}
Вложения
Тип файла: zip test_dict4.zip (38.4 Кб, 4 просмотров)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
zulkis
681 / 608 / 38
Регистрация: 13.01.2011
Сообщений: 1,724
15.06.2013, 15:57     Быстрое обращение к данным многомерных словарей #2
Безполезно. Почитайте документацию к LLVM 4.0+(CLang 3.1+). Это уже сделано до Вас.
И сделано лучше и лаконичнее.
Objective-C
1
[[[[_dict1 key:@"k1"] index:0] key:@"k3"] key:@"s4"];
Против
Objective-C
1
dict[@"k1"][0][@"k3"][@"s4"]
mobidevelop
182 / 182 / 3
Регистрация: 10.01.2013
Сообщений: 596
15.06.2013, 17:06     Быстрое обращение к данным многомерных словарей #3
zulkis прав. А кроме того, стандартные имена лучше описывают что именно этом методы делают. Набирать их не намного дольше (особенно, с использованием code completion), а читать намного проще. Тут было недавно побоище на похожую тему
А вот проверка индекса на корректность - это правильно. Только зря тип поменяли - в NSArray в качестве индекса NSUInteger используется. Если бы ваш метод принимал его, второе условие было бы просто не нужно.
Успехов!
noname_club
102 / 90 / 9
Регистрация: 01.05.2013
Сообщений: 583
15.06.2013, 19:12  [ТС]     Быстрое обращение к данным многомерных словарей #4
Цитата Сообщение от zulkis Посмотреть сообщение
Безполезно. Почитайте документацию к LLVM 4.0+(CLang 3.1+). Это уже сделано до Вас.
И сделано лучше и лаконичнее.
Objective-C
1
[[[[_dict1 key:@"k1"] index:0] key:@"k3"] key:@"s4"];
Против
Objective-C
1
dict[@"k1"][0][@"k3"][@"s4"]
очень странно что на всей странице

https://developer.apple.com/library/...s/NSArray.html

нету ни одного примера, использования массива "нормально" через [] скобки, кроме СИ массивов вроде таких
Objective-C
1
2
3
4
5
6
7
NSString *strings[3];
 
strings[0] = @"First";
 
strings[1] = @"Second";
 
strings[2] = @"Third";
https://developer.apple.com/library/...Reference.html

тоже самое тут, как будто все знают "правду" , но молчат

***

я провел ряд экспериментов
оказывается допускается, не только читать но и присваивать значения

1) массив

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
NSMutableArray *a = [NSMutableArray new]; // сейчас массив пуст
 
a[0] = @"hello 1"; // << строка записана успешно!
 
NSLog(@"str is %@", a[0]); // << строка прочитана успешно!
 
// если попытаться превысить диапазон то выскочит exception
 
a[1] = @"hello 2"; // << строка записана успешно!
a[10] = @"hello 3"; // << ERROR
 
// попытка присвоить nil
 
a[1] = nil; // << ERROR
2) словарь

Objective-C
1
2
3
4
5
6
7
8
9
10
11
NSMutableDictionary *d = [NSMutableDictionary new];
 
d[@"key1"] = @"hello1";
d[@"key2"] = @"hello2";
d[@"key3"] = @"hello3"; // успешно!
 
NSLog(@"str is %@", d[@"key2"]); // << строка прочитана успешно!
 
// попытка присвоить nil
 
d[@"key3"] = nil; // << ERROR
Вывод: использование [key] = value методов доступа к данным словарей и массивов сильно упрощает написание кода.

все выше указанное тестировалось на iOS 5 симуляторе xCode 4.6 с включенным ARC

Добавлено через 3 минуты
неужели нет никаких подводных камней? зачем эти громоздкие методы objectForKey: objectAtIndex:, которые, как выяснилось сейчас, безнадежно устарели и стали неудобны в использовании?
Vorona
Peace 2 all shining faces
668 / 530 / 45
Регистрация: 05.03.2010
Сообщений: 1,276
15.06.2013, 19:25     Быстрое обращение к данным многомерных словарей #5
Цитата Сообщение от noname_club Посмотреть сообщение
неужели нет никаких подводных камней? зачем эти громоздкие методы objectForKey: objectAtIndex:, которые, как выяснилось сейчас, безнадежно устарели и стали неудобны в использовании?
появились литералы, которые могут заменять эти методы вот и все
если память не изменяет, то стали доступны они в Xcode версии 4.5
почитайте про них тут: http://clang.llvm.org/docs/ObjectiveCLiterals.html

так же
Objective-C
1
2
3
4
5
6
@(-4.9); 
@YES; 
@8;
 
BOOL flag = NO;
NSNumber *flagNum = @(flag);
... заменяют методы класса NSNumber numberWithDouble: numberWithBool: numberWithInt: и т.д.

создание массивов
Objective-C
1
NSArray *array = @[@1, @2, @3];
создание словарей
Objective-C
1
NSDictionary *dict = @{@"key1":@"value1", @"key2":@"value2", @"key3":@"value3"};
и т.д.
noname_club
102 / 90 / 9
Регистрация: 01.05.2013
Сообщений: 583
15.06.2013, 22:09  [ТС]     Быстрое обращение к данным многомерных словарей #6
опираясь на офф документацию можно также добавить что оператор "[key] = value" теперь может быть переопределен и использован в "пользовательских" объектах или наследниках NSArray NSDictionary

Операторы индекса массивов
http://clang.llvm.org/docs/Objective...e-subscripting

Objective-C
1
2
3
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
 
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
Операторы ключа словарей
http://clang.llvm.org/docs/Objective...e-subscripting

Objective-C
1
2
3
- (id)objectForKeyedSubscript:(id)key;
 
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
Vorona
Peace 2 all shining faces
668 / 530 / 45
Регистрация: 05.03.2010
Сообщений: 1,276
15.06.2013, 23:22     Быстрое обращение к данным многомерных словарей #7
Цитата Сообщение от noname_club Посмотреть сообщение
опираясь на офф документацию можно также добавить что оператор "[key] = value" теперь может быть переопределен и использован в "пользовательских" объектах или наследниках NSArray NSDictionary
вот уж не думаю, так как опираясь на офф документацию, метод setObject:atIndexedSubscript: не является публичным и, соответсвенно, не может быть переопределен, потому максимум, чего можно добиться – это "value = [key]"

p.s. ну или если все-таки выгнуть свою палку и переопределить его, то ваше приложение дальше вашего компьютера не уйдет
noname_club
102 / 90 / 9
Регистрация: 01.05.2013
Сообщений: 583
16.06.2013, 00:08  [ТС]     Быстрое обращение к данным многомерных словарей #8
да, все просто упирается в невозможность унаследоваться от NSMutableArray

setObject:atIndexedSubscript:
незнаю как у него с видимостью, однако в пользовательских наследниках NSObject оператор
[key] = value работает нормально

myobject.h
Objective-C
1
2
3
4
5
6
7
8
#import <Foundation/Foundation.h>
 
@interface myobject : NSObject
 
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
 
@end
myobject.m
Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
#import "myobject.h"
 
@implementation myobject
 
- (id)objectAtIndexedSubscript:(NSUInteger)idx {
    NSLog(@"call to objectAtIndex %d",idx);
    return @"hello world";
}
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx {
    NSLog(@"try to set object %@ at index %d",obj,idx);
}
@end
Objective-C
1
2
3
4
myobject* mobj = [myobject new];
 mobj[0] = @200;
 mobj[10] = @300;
 NSLog(@"%@", mobj[10]);

2013-06-15 23:04:02.916 test_dict4[488:c07] try to set object 200 at index 0
2013-06-15 23:04:05.355 test_dict4[488:c07] try to set object 300 at index 10
2013-06-15 23:04:07.450 test_dict4[488:c07] call to objectAtIndex 10
2013-06-15 23:04:07.485 test_dict4[488:c07] hello world
Vorona
Peace 2 all shining faces
668 / 530 / 45
Регистрация: 05.03.2010
Сообщений: 1,276
16.06.2013, 01:47     Быстрое обращение к данным многомерных словарей #9
и никаких ворнингов?
noname_club
102 / 90 / 9
Регистрация: 01.05.2013
Сообщений: 583
23.07.2013, 22:08  [ТС]     Быстрое обращение к данным многомерных словарей #10
вернемся к теме.

если скажем класс категория с методами index и key или вовсе литералы могут облегчить сам вызов метода для доступа к элементу.

Однако что касается словарей. То метода key в этом случае становится недостаточно.

Так как у словарей есть ключи.

Objective-C
1
2
// доступ к элементу по ключу
id element = [dictionary key: @"elementKey"];
Причем эти ключи надо набирать в проекте до сотни раз! и каждый раз одни и теже.

Вот тут на помощь и приходят макросы.

давайте заставим Xcode подсказывать нам эти самые ключи по первым вводимым буквам

Обычно количество ключей в многомерном словаре невелико и может находится в пределах 20-30

пример ключей многомерного словаря реального приложения

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#define d_id @"id"
#define d_title @"title"
#define d_title2 @"title2"
#define d_info @"info"
 
#define d_items @"items"
 
#define d_usertext @"usertext"
#define d_type @"type"
#define d_data @"data"
#define d_visible @"visible"
#define d_level @"level"
#define d_mode @"mode"
#define d_tag @"tag"
 
// новые ключи
 
#define d_news @"news"
#define d_product @"product"
#define d_practic @"practic"
#define d_sid @"sid"
#define d_text @"text"
#define d_img @"img"
#define d_img2 @"img2"
#define d_imagedata @"imagedata"
#define d_tip @"tip"
#define d_description @"description"
#define d_description_sound @"description_sound"
#define d_theory @"theory"
 
....
после объявления сабжа в любом из глобальных синглтонов (ядра) приложения, становятся видны подсказки для ввода ключей

на рисунке пример реального кода с автоматической подсказкой для ввода ключа

Быстрое обращение к данным многомерных словарей

сравнение кода
Objective-C
1
2
id element = [dictionary key: @"elementKey"];
id element = [dictionary key: d_elementKey];
Нельзя не сказать, что данный подход имеет смысл только при очень частом использовании ключей словаря.

в остальных случаях достаточно строк @"ключ"
mobidevelop
182 / 182 / 3
Регистрация: 10.01.2013
Сообщений: 596
23.07.2013, 22:10     Быстрое обращение к данным многомерных словарей #11
Цитата Сообщение от noname_club Посмотреть сообщение
Причем эти ключи надо набирать в проекте до сотни раз! и каждый раз одни и теже.
Вот тут на помощь и приходят макросы.
Тут на помощь приходят сниппеты (Snippets). Научитесь, наконец, пользоваться средой разработки!

PS. Дальше даже читать не стал.
noname_club
102 / 90 / 9
Регистрация: 01.05.2013
Сообщений: 583
23.07.2013, 22:28  [ТС]     Быстрое обращение к данным многомерных словарей #12
Цитата Сообщение от mobidevelop Посмотреть сообщение
Тут на помощь приходят сниппеты (Snippets). Научитесь, наконец, пользоваться средой разработки!

PS. Дальше даже читать не стал.
http://ru.wikipedia.org/wiki/%D0%A1%...BF%D0%B5%D1%82

судя по вики

Сниппет (англ. snippet — фрагмент, отрывок) в практике программирования — небольшой фрагмент исходного кода или текста, пригодного для повторного использования. Сниппеты не являются заменой процедур, функций или других подобных понятий структурного программирования. Они обычно используются для более лёгкой читаемости кода функций, которые без их использования выглядят слишком перегруженными деталями, или для устранения повторения одного и того же общего участка кода
они не лучше/ не хуже макросов, даже можно считать макрос разновидностью Сниппета в данном подтексте.

Добавлено через 10 минут


судя по видео, "штука" хорошая, однако для подсказок именно ключей словарям в рамках одного проекта не годится
Vorona
Peace 2 all shining faces
668 / 530 / 45
Регистрация: 05.03.2010
Сообщений: 1,276
23.07.2013, 22:28     Быстрое обращение к данным многомерных словарей #13
да что вы развели тут с этими макросами, понятное дело, если строка или любое другое значение используется дважды и больше, то лучше вынести его в переменную или метод, дабы избежать копипаста, это же и макаке понятно, зачем расписывать это...??
естественно для начала нужно посмотреть или вообще стоит это выносить в глобальный для файла макрос, т.к. часто это признак пахнущего кода и можно обойтись передачей параметром или еще как-то

вообще разводили уже балаган по этому поводу с другим форумчанином и там приводилось достаточно доводов в пользу статических переменных вместо макросов, если без этого аж никак.
аналогично они подсвечиваются, только вот разница между ними существует
noname_club
102 / 90 / 9
Регистрация: 01.05.2013
Сообщений: 583
23.07.2013, 22:53  [ТС]     Быстрое обращение к данным многомерных словарей #14
т.к. часто это признак пахнущего кода и можно обойтись передачей параметром или еще как-то
ключ по параметру будете передавать?

приводилось достаточно доводов в пользу статических переменных вместо макросов
то есть мысль верная, неверная реализация из-за макросов? лучше использовать СИ константы?

довод против СИ констант : макрос имеет цвет отличающийся по цветовой гамме от обычных переменных -> лучше читаемость
довод за СИ константы: константы на уровне компилятора работают быстрее так как память уже под нее выделена и передается чисто указатель

есть 3-й путь
вызов СИ константы через макрос, однако тогда размер кода "инициализации ключей помощи" увеличиться в 2 раза,
что неприемлемо, если только не использовать какую нибудь утилиту для автоматизации процесса и не заполнения этого дела вручную

Добавлено через 14 минут
зачем расписывать это...
спрашиваете зачем "дефайнить" это... ?

да просто короче чем буква d_ трудно представить. Никакие синглтоны, объекты с полями не сравнить с быстротой реакции подсказки Xcode на ввод этих 2-3 символов!
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.07.2013, 22:57     Быстрое обращение к данным многомерных словарей
Еще ссылки по теме:
Обращение к данным из XML-файла C#
Таймер и параллельное обращение к данным C#
Delphi БД Обращение к данным ibQuery запроса
Java Обращение к данным класса из нескольких
C++ Обращение к данным другого объекта

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
mobidevelop
182 / 182 / 3
Регистрация: 10.01.2013
Сообщений: 596
23.07.2013, 22:57     Быстрое обращение к данным многомерных словарей #15
Когда Бог хочет меня наказать, он лишает кого-то разума
(с) Неизвестный Админ.
Yandex
Объявления
23.07.2013, 22:57     Быстрое обращение к данным многомерных словарей
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru