Переключатель Objective C с помощью объектов?

РЕШЕНИЕ

Следующий код работал для меня с jQuery. Он работает в каждом браузере и позволяет сохранять события и настраиваемые свойства.

var $el = $('#your-input-id');
$el.wrap('
').closest('form').get(0).reset(); $el.unwrap();

DEMO

См. этот jsFiddle для кода и демонстрации.

ССЫЛКИ

14
задан The Archetypal Paul 10 November 2008 в 14:01
поделиться

12 ответов

Я надеюсь, что Вы все простите мне за то, что рискнули здесь, но я хотел бы рассмотреть более общий вопрос парсинга XML-документов в Какао без потребности если еще операторы. Вопрос, как первоначально указано присваивает текст элемента тока переменной экземпляра символьного объекта. Как jmah указанный, это может быть решено с помощью кодирования значения ключа. Однако в более сложном XML-документе это не могло бы быть возможно. Рассмотрите, например, следующее.

<xmlroot>
    <corporationID>
        <stockSymbol>EXAM</stockSymbol>
        <uuid>31337</uuid>
    </corporationID>
    <companyName>Example Inc.</companyName>
</xmlroot>

существует несколько подходов к контакту с этим. Прочь вершины моей головы, я могу думать о двух использованиях NSXMLDocument. Первое использование NSXMLElement. Это довольно просто и не включает если еще проблема вообще. Вы просто получаете корневой элемент и проходите его именованные элементы один за другим.

NSXMLElement* root = [xmlDocument rootElement];

// Assuming that we only have one of each element.
[character setCorperationName:[[[root elementsForName:@"companyName"] objectAtIndex:0] stringValue]];

NSXMLElement* corperationId = [root elementsForName:@"corporationID"];
[character setCorperationStockSymbol:[[[corperationId elementsForName:@"stockSymbol"] objectAtIndex:0] stringValue]];
[character setCorperationUUID:[[[corperationId elementsForName:@"uuid"] objectAtIndex:0] stringValue]];

следующий использует более общий NSXMLNode, идет через дерево и непосредственно использует если еще структура.

// The first line is the same as the last example, because NSXMLElement inherits from NSXMLNode
NSXMLNode* aNode = [xmlDocument rootElement];
while(aNode = [aNode nextNode]){
    if([[aNode name] isEqualToString:@"companyName"]){
        [character setCorperationName:[aNode stringValue]];
    }else if([[aNode name] isEqualToString:@"corporationID"]){
        NSXMLNode* correctParent = aNode;
        while((aNode = [aNode nextNode]) == nil && [aNode parent != correctParent){
            if([[aNode name] isEqualToString:@"stockSymbol"]){
                [character setCorperationStockSymbol:[aNode stringValue]];
            }else if([[aNode name] isEqualToString:@"uuid"]){
                [character setCorperationUUID:[aNode stringValue]];
            }
        }
    }
}

Это - хороший кандидат на устранение, если еще структура, но как исходная проблема, мы не можем просто использовать случай переключателя здесь. Однако мы можем все еще устранить если еще при помощи performSelector. Первый шаг должен определить метод для каждого элемента.

- (NSNode*)parse_companyName:(NSNode*)aNode
{
    [character setCorperationName:[aNode stringValue]];
    return aNode;
}

- (NSNode*)parse_corporationID:(NSNode*)aNode
{
    NSXMLNode* correctParent = aNode;
    while((aNode = [aNode nextNode]) == nil && [aNode parent != correctParent){
        [self invokeMethodForNode:aNode prefix:@"parse_corporationID_"];
    }
    return [aNode previousNode];
}

- (NSNode*)parse_corporationID_stockSymbol:(NSNode*)aNode
{
    [character setCorperationStockSymbol:[aNode stringValue]];
    return aNode;
}

- (NSNode*)parse_corporationID_uuid:(NSNode*)aNode
{
    [character setCorperationUUID:[aNode stringValue]];
    return aNode;
}

волшебство происходит в invokeMethodForNode:prefix: метод. Мы генерируем селектор на основе названия элемента и выполняем тот селектор с анодом как единственный параметр. Престо бинго, мы избавили от необходимости если еще оператор. Вот код для того метода.

- (NSNode*)invokeMethodForNode:(NSNode*)aNode prefix:(NSString*)aPrefix
{
    NSNode* ret = nil;
    NSString* methodName = [NSString stringWithFormat:@"%@%@:", prefix, [aNode name]];
    SEL selector = NSSelectorFromString(methodName);
    if([self respondsToSelector:selector])
        ret = [self performSelector:selector withObject:aNode];
    return ret;
}

Теперь, вместо нашего большего, если еще оператор (тот, который дифференцировался между companyName и corporationID), мы можем просто записать одну строку кода

NSXMLNode* aNode = [xmlDocument rootElement];
while(aNode = [aNode nextNode]){
    aNode = [self invokeMethodForNode:aNode prefix:@"parse_"];
}

Теперь, я приношу извинения, если я понял какое-либо превратно из этого, это было некоторое время, так как я записал что-либо с NSXMLDocument, это поздно вечером, и я на самом деле не протестировал этот код. Таким образом, если Вы видите что-то не так, оставьте комментарий или отредактируйте этот ответ.

Однако я полагаю, что только что показал, как названный селекторами может использоваться в Какао, чтобы полностью устранить если еще операторы в случаях как это. Существует несколько глюков и угловых случаев. performSelector: семейство методов только берет 0, 1, или 2 метода аргумента, аргументами которых и типами возврата являются объекты, поэтому если типы аргументов и тип возврата не являются объектами, или если бы существует больше чем два аргумента, то необходимо было бы использовать NSInvocation для вызова его. Необходимо удостовериться, что имена методов, которые Вы генерируете, не собираются называть другие методы, особенно если цель вызова является другим объектом, и эта конкретная схема именования метода не будет работать над элементами с неалфавитно-цифровыми символами. Вы могли обойти это путем выхода из имен элементов XML в именах методов так или иначе, или путем создания NSDictionary использование имен методов как ключи и селекторы как значения. Это может стать довольно интенсивно использующим память и закончить тем, что заняло более длительное время. отправка performSelector как я описал, довольно быстро. Для очень большого, если еще операторы, этот метод может даже быть быстрее, чем если еще оператор.

12
ответ дан 1 December 2019 в 05:58
поделиться

В этом случае я не уверен, можно ли легко осуществить рефакторинг класс для представления полиморфизма, как Bradley предполагает, так как это - собственный Какао класс. Вместо этого Objective C способ сделать это должен использовать категорию класса для добавления elementNameCode метод к NSSting:

   typedef enum { 
       companyName = 0,
       companyID,  
       ...,
       Unknown
    } ElementCode;

    @interface NSString (ElementNameCodeAdditions)
    - (ElementCode)elementNameCode; 
    @end

    @implementation NSString (ElementNameCodeAdditions)
    - (ElementCode)elementNameCode {
        if([self compare:@"companyName"]==0) {
            return companyName;
        } else if([self compare:@"companyID"]==0) {
            return companyID;
        } ... {

        }

        return Unknown;
    }
    @end

В Вашем коде, Вы могли теперь использовать переключатель на [elementName elementNameCode] (и получить связанные предупреждения компилятора, если Вы забываете тестировать на одного из перечислимых участников и т.д.).

, Поскольку Bradley указывает, это не может стоить того, если логика используется только в одном месте.

1
ответ дан 1 December 2019 в 05:58
поделиться

То, что мы сделали в наших проектах, где нам нужно к так этому виду вещи много раз, должно настроить статический CFDictionary отображение строк/объектов для проверки по к простому целочисленному значению. Это ведет для кодирования, который похож на это:

static CFDictionaryRef  map = NULL;
int count = 3;
const void *keys[count] = { @"key1", @"key2", @"key3" };
const void *values[count] = { (uintptr_t)1, (uintptr_t)2, (uintptr_t)3 };

if (map == NULL)
    map = CFDictionaryCreate(NULL,keys,values,count,&kCFTypeDictionaryKeyCallBacks,NULL);


switch((uintptr_t)CFDictionaryGetValue(map,[node name]))
{
    case 1:
        // do something
        break;
    case 2:
        // do something else
        break;
    case 3:
        // this other thing too
        break;
}

при предназначении для Leopard только Вы могли бы использовать NSMapTable вместо CFDictionary.

1
ответ дан 1 December 2019 в 05:58
поделиться

Наиболее распространенный рефакторинг предложил для устранения, если еще или операторы переключения представляет полиморфизм (см. http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html ). Устранение таких условных выражений является самым важным, когда они дублированы. В случае XML, анализирующего как Ваш образец, Вы являетесь чрезвычайно движущимися данные к более естественной структуре так, чтобы Вы не должны были копировать условное выражение в другом месте. В этом случае, если еще или оператор переключения, вероятно, достаточно хорошо.

2
ответ дан 1 December 2019 в 05:58
поделиться

Существует на самом деле довольно простой способ иметь дело с расположением каскадом если еще операторы на языке как Objective C. Да, можно использовать разделение на подклассы и переопределение, создавая группу подклассов, которые реализуют тот же метод по-другому, вызывая корректную реализацию во времени выполнения с помощью общего сообщения. Это работает хорошо, если Вы хотите выбрать одну из нескольких реализаций, но она может привести к бесполезному быстрому увеличению подклассов, если у Вас есть много маленьких, немного отличающихся реализаций как Вы, имеют тенденцию иметь в длинном если еще или операторы переключения.

Вместо этого факторизуйте тело каждого if/else-if пункта в его собственный метод, все в том же классе. Назовите сообщения, которые вызывают их подобным способом. Теперь создайте NSArray, содержащий селекторы тех сообщений (полученное использование @selector ()). Принудите строку, Вы тестировали в условных выражениях в использование селектора NSSelectorFromString () (Вы, возможно, должны связать дополнительные слова или двоеточия к нему сначала в зависимости от того, как Вы назвали те сообщения, и берут ли они аргументы). Теперь имейте сам, выполняют селектор с помощью performSelector:.

Этот подход имеет оборотную сторону, что это может создать помехи классу многими новыми сообщениями, но, вероятно, лучше создать помехи единому классу, чем вся иерархия классов с новыми подклассами.

3
ответ дан 1 December 2019 в 05:58
поделиться

if-else реализация, которую Вы имеете, является правильным способом сделать это, так как switch не будет работать с объектами. Кроме того, чтобы возможно быть немного более твердым читать (который субъективен), нет никакой реальной оборотной стороны в использовании if-else операторы этот путь.

3
ответ дан 1 December 2019 в 05:58
поделиться

Одним путем я сделал, это с NSStrings при помощи NSDictionary и перечислений. Это не может быть самым изящным, но я думаю, что это делает код немного более читаемым. Следующий псевдокод извлечен от один из моих проектов :

typedef enum { UNKNOWNRESIDUE, DEOXYADENINE, DEOXYCYTOSINE, DEOXYGUANINE, DEOXYTHYMINE } SLSResidueType;

static NSDictionary *pdbResidueLookupTable;
...

if (pdbResidueLookupTable == nil)
{
    pdbResidueLookupTable = [[NSDictionary alloc] initWithObjectsAndKeys:
                          [NSNumber numberWithInteger:DEOXYADENINE], @"DA", 
                          [NSNumber numberWithInteger:DEOXYCYTOSINE], @"DC",
                          [NSNumber numberWithInteger:DEOXYGUANINE], @"DG",
                          [NSNumber numberWithInteger:DEOXYTHYMINE], @"DT",
                          nil]; 
}

SLSResidueType residueIdentifier = [[pdbResidueLookupTable objectForKey:residueType] intValue];
switch (residueIdentifier)
{
    case DEOXYADENINE: do something; break;
    case DEOXYCYTOSINE: do something; break;
    case DEOXYGUANINE: do something; break;
    case DEOXYTHYMINE: do something; break;
}
4
ответ дан 1 December 2019 в 05:58
поделиться

Смейте я предлагаю использовать макрос?

#define TEST( _name, _method ) \
  if ([elementName isEqualToString:@ _name] ) \
    [character _method:currentElementText]; else
#define ENDTEST { /* empty */ }

TEST( "companyName",      setCorporationName )
TEST( "setCorporationID", setCorporationID   )
TEST( "name",             setName            )
:
:
ENDTEST
7
ответ дан 1 December 2019 в 05:58
поделиться

Если Вы хотите использовать как можно меньше код, и Ваши имена элементов и методы set все называют так, чтобы, если elementName "нечто" затем, метод set был setFoo: Вы могли сделать что-то как:

SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", [elementName capitalizedString]]);

[character performSelector:selector withObject:currentElementText];

или возможно ровный:

[character setValue:currentElementText forKey:elementName]; // KVC-style

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

[Редактирование: вторая опция была уже упомянута кем-то; ой!]

7
ответ дан 1 December 2019 в 05:58
поделиться

Необходимо использовать в своих интересах Кодирование Значения ключа:

[character setValue:currentElementText forKey:elementName];

, Если данные недоверяемы, Вы могли бы хотеть проверить, что ключ допустим:

if (![validKeysCollection containsObject:elementName])
    // Exception or error
13
ответ дан 1 December 2019 в 05:58
поделиться

Хотя существует не обязательно лучший способ сделать что-то как этот для одного использования времени, почему использование "выдерживает сравнение", когда можно использовать "isEqualToString"? Это, казалось бы, было бы более производительным, так как сравнение остановится в первом символе несоответствия, вместо того, чтобы пройти все это для вычисления допустимого результата сравнения (хотя задумано о нем, сравнение могло бы быть ясным в той же точке) - также, хотя это будет выглядеть немного более чистым, потому что тот вызов возвращает BOOL.

if([elementName isEqualToString:@"companyName"] ) 
  [character setCorporationName:currentElementText]; 
else if([elementName isEqualToString:@"corporationID"] ) 
  [character setCorporationID:currentElementText]; 
else if([elementName isEqualToString:@"name"] ) 
3
ответ дан 1 December 2019 в 05:58
поделиться

Posting this as a response to Wevah's answer above -- I would've edited, but I don't have high enough reputation yet:

unfortunately the first method breaks for fields with more than one word in them -- like xPosition. capitalizedString will convert that to Xposition, which when combined with the format give you setXposition: . Definitely not what was wanted here. Here is what I'm using in my code:

NSString *capName = [elementName stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[elementName substringToIndex:1] uppercaseString]];
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", capName]);

Not as pretty as the first method, but it works.

3
ответ дан 1 December 2019 в 05:58
поделиться