Вызывается ли nsinvocation?

Я новичок в разработке объективов c и iphone. Я был в замешательстве. Я пытаюсь создать кнопку, которая создается во время выполнения, после нажатия другой кнопки, и приложение этого не знает:

 -(void)button4Pushed{
    NSLog(@"Button 4 pushed\n");
    Class cls = NSClassFromString(@"UIButton");//if exists {define class},else cls=nil
    id pushButton5 = [[cls alloc] init];

    CGRect rect =CGRectMake(20,220,280,30);
    NSValue *rectValue = [NSValue valueWithCGRect:rect];


    //--------------1st try set frame  - work,but appears at wrong place
    //[pushButton5 performSelector:@selector(setFrame:) withObject:rectValue];
    //--------------2nd try set frame  + this work correctly
    [pushButton5 setFrame: CGRectMake(20,220,280,30)];                    



    //this work correct [pushButton5 performSelector:@selector(setTitle:forState:) withObject:@"5th Button created by 4th" withObject:UIControlStateNormal];
    //but i need to use invocation to pass different parameters:

    NSMethodSignature *msignature;
    NSInvocation *anInvocation;

    msignature = [pushButton5 methodSignatureForSelector:@selector(setTitle:forState:)];
    anInvocation = [NSInvocation invocationWithMethodSignature:msignature];

    [anInvocation setTarget:pushButton5];
    [anInvocation setSelector:@selector(setTitle:forState:)];

    NSNumber* uicsn =[NSNumber numberWithUnsignedInt:UIControlStateNormal];
    NSString *buttonTitle = @"5thbutton";

    [anInvocation setArgument:&buttonTitle atIndex:2];
    [anInvocation setArgument:&uicsn atIndex:3];
    [anInvocation retainArguments];
    [anInvocation invoke];

    [self.view addSubview:(UIButton*)pushButton5];
}

Что я делаю неправильно? Вызов вызывается, но результата нет... Я знаю, что могу создать его так:

    UIButton *pushButton3 = [[UIButton alloc] init];
    [pushButton3 setFrame: CGRectMake(20, 140, 280, 30)];
    [pushButton3 setTitle:@"I'm 3rd button!created by 2nd" forState:UIControlStateNormal];
    [self.view addSubview:pushButton3];

Но мне нужно использовать вызов, и я не знаю, почему он не работает?

Спасибо за вашу помощь.


person Alexander    schedule 10.08.2011    source источник


Ответы (2)


Вы устанавливаете NSNumber * в качестве второго аргумента, но метод, который вы пытаетесь вызвать (эффективно), требует int. Используйте свой точно такой же код, но вместо этого попробуйте эти строки:

UIControlState uicsn = UIControlStateNormal;

// тогда

[anInvocation setArgument:&uicsn atIndex:3];
person Perception    schedule 10.08.2011
comment
Ты прав. Большое спасибо. Я использовал NSNumber для переноса UIControlState, потому что мне действительно нужно передать его в NSArray, а затем получить из NSValue. Я провел 2 дня, но я не могу понять, как это сделать. - person Alexander; 11.08.2011
comment
@ Александр - нет проблем, рад, что теперь это работает для тебя. Не знаю, решили ли вы уже другую проблему, но вы всегда можете обернуть и сохранить UIControlState после NSInvocation. В любом случае, удачи и не забудьте принять любой ответ, который, по вашему мнению, помог вам больше всего! - person Perception; 11.08.2011
comment
Восприятие, с помощью ребят, проблема передачи UIControlState в функцию путем его обертывания была решена. Вы можете прочитать об этом здесь - person Alexander; 15.08.2011

Зачем вам нужно использовать вызов?

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

NSInvocation — это строительный блок среды выполнения/класс последней инстанции; вы должны использовать другие доступные вам инструменты, такие как протоколы (если у объекта есть метод) и блоки или указатели функций (если вам просто нужна бестелесная функция), если вы вообще можете управлять окружающими объектами.

Ответ Perception решает техническую проблему, но вы можете все усложнить для себя.

person Jesper    schedule 10.08.2011
comment
Пожалуйста, не публикуйте ответы, содержащие вопросы. Вместо этого добавьте комментарий к вопросу. - person DarkDust; 10.08.2011
comment
@DarkDust: я планировал обновить его ответом, как только Александр прокомментировал. К сожалению, я отвлекся. - person Jesper; 10.08.2011
comment
@Jesper: Тем не менее, в StackOverflow у нас есть правило (этикет), согласно которому ответы должны быть ответы. Ваш запрос на разъяснение (зачем вам нужно использовать вызов) и ответ на него представляет интерес для всех, кто хочет дать ответ, и поэтому должен быть приложен непосредственно к вопросу в качестве комментария. Поэтому, пожалуйста, оставьте комментарий в следующий раз, а затем дайте ответ. Спасибо. - person DarkDust; 10.08.2011
comment
@Jesper, я хочу написать функцию, которая получает следующие параметры: объект id, имя метода NSString, параметры NSArray*, (id) resObj. И для объекта он сделает любой метод с переданными параметрами, результат запишет в resObj и вернет, была ли функция выполнена или нет. PerformSelector может иметь только 3 параметра (withObject:). И это можно сделать только вызовами, потому что у него есть метод setArgument:, который я могу использовать в цикле for. - person Alexander; 15.08.2011
comment
@Alexander: Вам не нужен NSInvocation для этого, вы можете просто использовать objc_msgSend. Я согласен, что NSInvocation в этом случае немного проще, если вы начинаете с нуля. Но я все же думаю, что проблему можно было бы решить гораздо проще, если изменить код на использование протоколов или блоков. - person Jesper; 16.08.2011
comment
@Jasper: Я думал об этом, но не могу понять, как перейти к obj_msgSend нескольким параметрам, количество которых я не знаю. И с помощью NSInvocation я могу добавить их динамически, используя setArgument:atIndex:. Хотя obj_msgSend работает быстрее, не так ли? - person Alexander; 17.08.2011
comment
@Alexander: NSInvocation вызывает objc_msgSend за кулисами. Мне кажется, вы точно знаете, сколько у вас параметров. Что вам нужно сделать, так это позвонить objc_msgSend(<the object>, <the method/message selector>, <every other parameter in order>). В вашем случае это будет objc_msgSend(pushButton5, @selector(setTitle:forState:), buttonTitle, UIControlStateNormal). В частности, в этом случае я не понимаю, почему бы вам просто не использовать [pushButton5 setTitle:buttonTitle forState:UIControlStateNormal]. - person Jesper; 17.08.2011