0

I want to create a pickerView programmatically and have it use it's own version of a method like pickerView:numberOfRowsInComponent.

I create the instance at runtime like this:

UIPickerView *myPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 200, 320, 200)];
myPickerView.delegate = self;
myPickerView.dataSource = self;
myPickerView.showsSelectionIndicator = YES;
[self.view addSubview:myPickerView];

The standard method called would be:

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    NSUInteger numRows = 5;
    return numRows;
}    

What I want to do is replace this standard method with another method for this instance only.

-(NSInteger)xxxpickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{ // special method for this instance only
    return 1;
}

I've been able to use method swizzle to do this with other things, but I can't seem to get it to work with UIPickerView.

@implementation UIPickerView (Tracking)
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];
        SEL originalSelector =   @selector(pickerView:numberOfRowsInComponent:);
        SEL swizzledSelector = @selector(xxxpickerView:numberOfRowsInComponent:);

      Method originalMethod = class_getInstanceMethod(class, originalSelector);
      Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
      BOOL didAddMethod =
      class_addMethod(class,
                    originalSelector,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));

      if (didAddMethod) {
          class_replaceMethod(class,
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
      } else {
          method_exchangeImplementations(originalMethod, swizzledMethod);
      }

  });

}

I've listed the methods to see if the 2nd method was added to the instance during runtime and it is in the list.

However, the 2nd method doesn't run, the 1st method does run.

Here's a link to the post that got me started on this, and I've confirmed it works, but I seem to be missing something about this. http://nshipster.com/method-swizzling/

I'm open to other suggestions, the problem I'm trying to solve is that I want to create the instance of a UIPickerView object that won't be dependent on another instance that will be running at the same time. So I want a different method that will work only with the one instance and completely ignore any other instances that might be running and I want to do this programmatically.

At lest one reason for not using a tag/switch, is that I don't know what the conditions will be until runtime.

I don't know why swizzle would work with one object and not another, and I'm open to other way to replace stock methods with others at runtime.

Is there something about the method I'm trying to replace that won't allow it to be replaced?

EDIT: in order to try and make the question clear, the following code in the link works. It swaps one method for another method. What I need to do is the same thing for another object and I can't figure out what it works for 1 object and not another.

This works for another object: http://nshipster.com/method-swizzling/

Here's another link as well: http://blog.newrelic.com/2014/04/16/right-way-to-swizzle/

KarlJay
  • 79
  • 1
  • 9

1 Answers1

0

One simple way to do it is keep a copy of the pointer in a property and then compare pointers in the datasource/delegate methods.

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    if ( pickerView == self.myPickerView )
        return 1;   // response for this particular picker view
    else
        return 5;   // standard response
}
user3386109
  • 34,287
  • 7
  • 49
  • 68
  • 1
    Or perhaps using tag or some other unique way of recognizing the picker, as swizzling seems too much of a hassle in this case... – Lior Pollak Mar 01 '15 at 09:33
  • I've used this before and you're right, it will do the job for most cases, but what I need is to get the pickerView to run a different method other than the standard one. The swizzle approach will swap one method for another method as shown in the link above, I just need to find out why this works for one object and not another. It works fine for UIView, but not UIPickerView. I'm wondering if I must subclass UIPickerView 1st. – KarlJay Mar 01 '15 at 10:46
  • Maybe I'm going the wrong way here. This is what I want to do: Create several instances of a class (ie UIPickerView) such that each instance of the class has it's own methods. As it works now, they share methods, I want them to have their own unique methods. They'll be created at runtime and the code each method uses will be determined at runtime. – KarlJay Mar 01 '15 at 13:31
  • The `UIPickerView` class has an instance method called `numberOfRowsInComponent`. The `UIPickerViewDataSource` protocol has a method called `pickerView:numberOfRowsInComponent`. You're getting the two confused. – user3386109 Mar 02 '15 at 07:04