Проблемы Objective-C с NSDictionary и NSURL
-
21-08-2019 - |
Вопрос
Я новичок в 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'
Любая помощь будет оценена по достоинству.Спасибо.
Решение
А ключ это то, что вы используете для доступа к объект в словаре.У вас меняются местами ключи и объекты в каждой строке, которую вы вызываете. -[bookmarks setObject:... forKey...]
в коде.Проблема в вашем случае возникает потому, что вы пытаетесь рассматривать объекты NSURL как объекты NSString — [bookmarks objectForKey:(NSString *)each]
— и словарь пытается получить длину предполагаемой строки, вызывая -length
, который существует для NSString, но не для NSURL.
Если вы всегда создаете словарь с одними и теми же объектами, рассмотрите возможность использования более компактного конструктора varargs для NSDictionary
.(Обратите внимание, что последний аргумент, разделенный запятыми, должен быть равен нулю — см. соответствующая документация) Вы также можете использовать -[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]);
}
Другие советы
У вас отменена инициализация словаря закладок:
[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 напрямую, вместо того, чтобы сначала получать ключи (хотя вам вполне могут понадобиться ключи по какой-то другой причине).
Я думаю, что вы ссылаетесь на неправильную переменную в цикле while, пытаясь получить URL-адрес (и я думаю, вам следует использовать 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);
}
Я работаю над теми же онлайн-классами и обнаружил, что ни один из приведенных выше ответов, похоже, не работает либо потому, что NSEnumerator может не реагировать на objectForKey, либо потому, что конкретный тип перечисления не поддерживается (возможно, не в iPhone SDK по сравнению с OSX i). не знаю).Однако я заставил его работать как шарм следующим образом...
NSString *aKey;
NSEnumerator *keyEnumerator = [bookmarks keyEnumerator];
NSURL *url;
while (aKey = [keyEnumerator nextObject])
{
url = [bookmarks objectForKey:aKey];
NSLog(@"value: %@", [url absoluteURL]);
}