Objective-C Проблемы с NSDictionary и NSURL - PullRequest
2 голосов
/ 29 июня 2009

Я новичок в Objective-C и понятия не имею, почему этот код не работает:

    NSMutableDictionary *bookmarks = [NSMutableDictionary dictionaryWithCapacity:(NSUInteger) 4];
[bookmarks setObject:@"Stanford University" forKey:[NSURL URLWithString:(NSString *) @"http://www.stanford.edu"]];
[bookmarks setObject:@"Apple" forKey:[NSURL URLWithString:(NSString *) @"http://www.apple.com"]];
[bookmarks setObject:@"Berkeley" forKey:[NSURL URLWithString:(NSString *) @"http://www.berkeley.edu"]];
[bookmarks setObject:@"CS193P" forKey:[NSURL URLWithString:(NSString *) @"http://cs193p.stanford.edu"]];

NSEnumerator *browser = [bookmarks keyEnumerator];
id each;
NSURL *url;
while ((each = [browser nextObject])) {
    url = [browser valueForKey:(NSString *)each];
    NSLog(@"%@", [url absoluteURL]);
}

Я получаю ошибку:

2009-06-29 11:25:22.844 WhatATool[2102:10b] *** -[NSURL length]: unrecognized selector sent to instance 0x1072c0
2009-06-29 11:25:22.845 WhatATool[2102:10b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL length]: unrecognized selector sent to instance 0x1072c0'

Любая помощь будет оценена. Спасибо.

Ответы [ 4 ]

10 голосов
/ 29 июня 2009

A key - это то, что вы используете для доступа к объекту в словаре. Ваши ключи и объекты меняются местами в каждой строке, которую вы называете -[bookmarks setObject:... forKey...] в коде. Проблема в вашем случае возникает потому, что вы пытаетесь обработать объекты NSURL как объекты NSString - [bookmarks objectForKey:(NSString *)each] - и словарь пытается получить длину предполагаемой строки, вызывая -length, которая существует для NSString, но не для NSURL .

Если вы всегда создаете словарь с одними и теми же объектами, рассмотрите возможность использования более компактного конструктора varargs для NSDictionary. (Обратите внимание, что последний аргумент, разделенный запятыми, должен быть nil - см. соответствующую документацию ). Вы также можете использовать -[NSDictionary dictionaryWithObjects:forKeys:] с двумя объектами NSArray, содержащими URL-адреса и имена закладок. (Между прочим, приведение строковых литералов как NSString* для создания NSURL совершенно не требуется.)

NSDictionary *bookmarks = [NSDictionary dictionaryWithObjectsAndKeys:
                           [NSURL URLWithString:@"http://www.stanford.edu"],
                           @"Stanford University",
                           [NSURL URLWithString:@"http://www.apple.com"],
                           @"Apple",
                           [NSURL URLWithString:@"http://www.berkeley.edu"],
                           @"Berkeley",
                           [NSURL URLWithString:@"http://cs193p.stanford.edu"],
                           @"CS193P",
                           nil];

Кроме того, у вас есть скрытая ошибка, которая еще не была упомянута: browser - это NSEnumerator, но вы звоните valueForKey:, как будто это было NSDictionary, а не bookmarks. Это вызовет аналогичный сбой и для нераспознанного селектора. (Даже для объектов словаря вы должны вместо этого вызывать -objectForKey:; -valueForKey: используется в основном для / от привязок какао , и выполняет дополнительную работу, которая вам не нужна. Я понимаю, что это сбивает с толку, так как мы думаем в терминах «пары ключ-значение», но это так…)

Наконец, вы также можете несколько упростить код перечисления. (Цикл for-in в NSDictionary перечисляет свои ключи так же, как -keyEnumerator.)

Вот как я бы предложил сделать последнюю часть:

NSURL *url
for (NSString *key in bookmarks) {
    url = [bookmarks objectForKey:key];
    NSLog(@"%@", [url absoluteURL]);
}
3 голосов
/ 29 июня 2009

Инициализация словаря закладок отменена:

[bookmarks setObject:@"Stanford University" forKey:[NSURL URLWithString:(NSString *) @"http://www.stanford.edu"]];

Должно быть:

[bookmarks setObject:[NSURL URLWithString:(NSString *) @"http://www.stanford.edu"] forKey:@"Stanford University"];

Также есть более простой способ сделать перечисление:

NSURL *url;
for ( NSString *each in [bookmarks allKeys] ) 
{
        url = [browser objectForKey:(NSString *)each];
        NSLog(@"%@", [url absoluteURL]);
}

Вы также можете перечислить через [bookmarks allValues], чтобы получить объект URL напрямую, вместо того, чтобы сначала извлекать ключи (хотя вам может понадобиться ключи по какой-то другой причине).

1 голос
/ 15 августа 2009

Я работаю через те же онлайн-классы и обнаружил, что ни один из приведенных выше ответов, похоже, не работает либо потому, что NSEnumerator может не отвечать на objectForKey, либо потому, что определенный тип перечисления не поддерживается (возможно, не в iPhone SDK по сравнению в OSX я не знаю). Я получил это, чтобы работать как очарование следующим образом, хотя ...

NSString *aKey;
NSEnumerator *keyEnumerator = [bookmarks keyEnumerator];
NSURL *url;

while (aKey = [keyEnumerator nextObject])
{
    url = [bookmarks objectForKey:aKey];
    NSLog(@"value: %@", [url absoluteURL]);
}
1 голос
/ 29 июня 2009

Я думаю, что вы пытаетесь получить URL-адрес в неправильной переменной в цикле while (и я думаю, что вы должны использовать селектор objectForKey:, чтобы получить значение NSDictionary, а не valueForKey:):

NSEnumerator *browser = [bookmarks keyEnumerator];
id each;
NSURL *url;
while ((each = [browser nextObject])) {
    url = [bookmarks objectForKey:(NSString *)each]; // <-- bookmarks, not browser
    NSLog(@"URL = %@", url);
}
...