Как динамически настраивать имена и вызовы методов с помощью Objective-C

Я пытаюсь сжать свой код для метода, и мне было интересно, как я смогу достичь следующего:

У меня есть несколько переменных, которые отличаются только своим количеством, например:

int intVariable1
int intVariable2
UILabel Label1
UILabel Label2
BOOL bool1
BOOL bool2

и Т. Д.

Итак, я хочу вызвать метод и передать int. Этот int будет определять, над какими целыми числами, UILablels и BOOL будут работать. Таким образом, если бы в методе была передана 1, эти переменные работали бы следующим образом:

- (void) DyanamicMethod: (int) inputNumber {
     //something that uses the inputNumber to act on the 1 variables

     intVariable1 = someValue;
     [Label1 setText:someText];
     bool1 = YES;
}

Очевидно, что если бы было передано 2, я бы хотел, чтобы переменные были 2-го типа. Я предполагаю, что вы каким-то образом сделаете что-то с созданием строки, но я не уверен, как это настроить, чтобы использовать ее в качестве имени переменной. Любое понимание будет оценено. Спасибо за уделенное время.


person MarcZero    schedule 17.01.2010    source источник


Ответы (5)


Объявите переменные как массивы:

int intVariable[2];
UILabel *Label[2];
BOOL bools[2];

Тогда метод будет выглядеть так:

intVariable[inputNumber] = someValue;
[Label[inputNumber] setText:@"someText"];
bools[inputNumber] = YES;

Имейте в виду, что индексы массивов отсчитываются от нуля, поэтому в массивах выше переменная «1» имеет индекс 0, а переменная «2» - индекс 1. Ваш метод также может просто взять inputNumber и вычесть из него единицу, чтобы получить индекс массива.

person Community    schedule 17.01.2010
comment
На самом деле я всегда оставляю свои пронумерованные переменные равными 0, поэтому переключение должно быть простым. Выглядит хорошо. Я скорректирую свой код и попробую это. Спасибо. - person MarcZero; 17.01.2010
comment
Единственным недостатком здесь является то, что вы не сможете настроить свои IBOutlets в IB с массивами. - person Ben Gottlieb; 17.01.2010
comment
Зачем использовать массивы в стиле C вместо NSArray? Используя NSArray, вы можете использовать быстрое перечисление для перебора содержащихся в нем значений. - person James; 17.01.2010
comment
Бен, Джеймс: Спасибо, это хорошие моменты. Исходя из требований, выберите наиболее подходящий метод. - person ; 17.01.2010
comment
да. Я пробовал это, и до сих пор это не играет хорошо. Возможно, мне стоит попробовать использовать NSArray вместо массива C. - person MarcZero; 17.01.2010
comment
Хорошо, не могли бы вы подробнее рассказать о проблеме, с которой столкнулись? - person ; 17.01.2010
comment
@James: NSArray медленнее, NSArray не строго типизирован, NSArray не может хранить BOOL-s и int-s изначально, доступ к элементам в NSArray болезненен, NSArray использует дополнительное пространство кучи, NSArray не может хранить nil напрямую, быстрое перечисление NSArray занимает много больше места для кода и немного больше времени, чем при обычном перечислении C, NSArray хранить данные нелокально по сравнению с массивом C, вы не можете узнать размер NSArray, пока не -count, что снова занимает больше места и времени для кода, и т. д. и т. д. - person kennytm; 17.01.2010
comment
Честно говоря, NSArray выполняет проверки границ, которые могут сэкономить много уязвимостей из-за ленивых программистов. (и NSArray его размер может быть определен во время выполнения, но здесь он не входит в область видимости.) - person kennytm; 17.01.2010
comment
Кенни, конечно, первое, о чем должен беспокоиться программист, - это удобочитаемость? Лично я считаю, что с NSArray намного проще работать и понимать, такие команды, как: [arrayName insertObject:] невероятно удобны. Я согласен, что отсутствие строгой типизации может быть проблемой ... - person James; 18.01.2010
comment
DyingCactus: Я новичок в Objective-C и ошибках, которые он производит, но я считаю, что основные проблемы, с которыми я столкнулся, были связаны с синтезированными геттерами и сеттерами. Я не мог синтезировать массивный объект. Невозможно связать объект в IB тоже было бы проблематично, хотя я и не пытался этого сделать. Я отменил свои шаги до настройки массива и хочу попробовать что-нибудь еще. Я сейчас читаю варианты, перечисленные здесь всеми. - person MarcZero; 18.01.2010
comment
MarcZero, похоже, вам придется использовать здесь комбинацию решений. NSArrays легче превратить в свойства (хотя такое раскрытие переменных класса может быть не идеальным решением). Как отметил Бен, массивы C и NSArray не могут использоваться в качестве IBOutlets (но пользовательский интерфейс может быть создан и подключен программно без IB). В любом случае, массивы C находят свое применение, и я надеюсь, что это кому-то помогло. - person ; 18.01.2010
comment
@James: Во-первых, -insertObject: не принадлежит NSArray. NSArray неизменен. NSMutableArray имеет гораздо больше преимуществ, чем динамические массивы C. Во-вторых, эти команды понятны, да, но раздражают, когда они часто нужны (например, [arr objectAtIndex:4] vs arr[4]). Но, может быть, стоит напомнить вам, что -objectAtIndex: включает в себя (относительно) дорогостоящий поиск в таблице, косвенные вызовы функций, блокировку и т. Д., В то время как a[x] - это просто простое добавление и разыменование указателя. - person kennytm; 18.01.2010
comment
DyingCactus: поскольку это не нужно для того, чтобы мой код работал, а только для того, чтобы сжать его и сделать более читабельным, я решил вернуться к этой проблеме позже, когда мне будет удобнее работать с SDK и Objective-C. Придется потратить некоторое время и научиться настраивать торговые точки вручную без IB. Спасибо за вашу помощь и постоянную помощь. - person MarcZero; 18.01.2010

Вы можете использовать кодирование "ключ-значение".

- (void) DyanamicMethod: (int) inputNumber {
     //something that uses the inputNumber to act on the 1 variables

     NSString* key = [NSString stingWithFormat:@"Label%i", number];
     UILabel* label = [self valueForKey:key];
     label.text = newString;
}
person gcamp    schedule 17.01.2010
comment
Умм, я не знал о valueForKey Дополнительная информация здесь: stackoverflow.com/questions/1062183/ - person Eld; 17.01.2010

Если вам нужно что-то подобное, вы можете сохранить NSArray всех меток ... Как в разделе интерфейса класса:

NSArray* labels ;

В init: (или loadView)

labels = [[NSArray alloc] initWithObjects:Label1, Label2,etc] ;

В dealloc:

[labels release] ;

в DyanamicMethod: (int) inputNumber

UILabel* label = [labels objectAtIndex:inputNumber] ;

Повторите для каждого типа ... Или создайте новый класс, содержащий метку, int и bool, и сделайте массив этого типа.

Другой способ:
Создать свойства для каждой из ваших переменных-членов.
Затем в вашей функции:

UILabel label1 = [self performSelector:sel_getUid([[NSString stringWithFormat:@"label%d", inputNumber] UTF8String])] ;

Я думаю, что в этой ситуации лучше использовать какой-либо массив, но это возможно. См. Документация NSObject для performSelector.

person Eld    schedule 17.01.2010

Вы можете сделать это с помощью свойств (ну, вам не НУЖНЫ свойства, но они упростят), хотя вам придется переключиться на объекты:

@property (nonatomic, readwrite, retain) NSNumber *variable1, *variable2;
@property (nonatomic, readwrite, retain) NSNumber *bool1, *bool2;
@property (nonatomic, readwrite, retain) UILabel *label1, *label2;

- (void) DyanamicMethod: (int) inputNumber { 
    [[self valueForKey: [NSString stringWithFormat: @"label%d", inputNumber] setText: someText];
    [self setValue: [NSNumber numberWithInt: inputNumber] 
            forKey: [NSString stringWithFormat: @"variable%d", inputNumber]];
    [self setValue: [NSNumber numberWithBool: YES] 
            forKey: [NSString stringWithFormat: @"bool%d", inputNumber]];
}
person Ben Gottlieb    schedule 17.01.2010
comment
Вам не нужны @propertys для участия в KVC. - person kennytm; 17.01.2010
comment
@KennyTM: Либо свойства, либо самокодирующиеся аксессоры, но это не имеет отношения к ответу Бена. - person Georg Schölly; 17.01.2010
comment
Да, я упоминал, что они тебе не НУЖНЫ, но это немного упростит жизнь. - person Ben Gottlieb; 17.01.2010
comment
@Georg: На самом деле ivar с именем variable1 или _variable1 достаточно, чтобы использовать KVC для ключа variable1. Нет необходимости определять какие-либо аксессоры. - person kennytm; 17.01.2010

У вас слишком много переменных для простого оператора switch?

switch(inputNumber) {
  case 1:
    intVariable1 = someValue;
    [Label1 setText:someText];
    bool1 = YES;
    break;
  case 2:
    intVariable2 = someValue;
    [Label2 setText:someText];
    bool2 = YES;
    break;
// etc
}
person sbooth    schedule 17.01.2010
comment
Не слишком много. Я мог бы сделать это так. Я делал это с помощью ряда операторов if. Я мог бы предположить, что есть способ сделать это динамически, но я ничего не вижу в своих поисках. Я не уверен, что использую правильные условия поиска. Я просто пытаюсь сжать свой код, если это возможно. - person MarcZero; 17.01.2010