0

I'm trying to set up an app that works with UIPageViewController. I technically could instantiate all the view at once and put them in an array, but that would be expensive, and it seems better to initialize the views as needed. I read that an NSInvocation is a message rendered static-- so I was thinking I could have an array that basically contains: [SubclassA alloc]init], [SubclassB alloc]init], etc... with those messages wrapped in an NSInvocation. I could then return the result of that message in pageViewController:ViewControllerAfter/BeforeViewController:.

I'm still pretty new at this, so it is very possible I am fundamentally misunderstanding NSInvocation, but either way, an answer would still be helpful.

PopKernel
  • 4,110
  • 5
  • 29
  • 51
  • I think what you're misunderstanding is UIPageViewController. There's no need to pre-store any invocations. Just respond as delegate by figuring out what view controller is needed, and create it, configure it, and return it. – matt Jun 21 '14 at 14:59
  • I know, but I thought maybe the best way was to store those calls in an array and return them by index. – PopKernel Jun 21 '14 at 15:01
  • the idea of the delegation pattern is that you create the view controllers as needed and UIPageViewController holds those needed and releases the ones that aren't needed any more. Pre-creating / configuring VCs is OK for a few (2-4) but keep in mind that once they are displayed, they retain the complete view hierarchy and fill up memory. – Martin Ullrich Jun 21 '14 at 15:05
  • 1
    Is there any specific reason you don't want a switch-case statement or a few ifs inside your delegate method? If it works and isn't too large or can be split up easily (e.g. like `if (..) { return [self createA]; } else { return [self createB] }`) this would be unnecessary over-engineering – Martin Ullrich Jun 21 '14 at 15:09
  • 1
    I know what you thought. Try to bear in mind that you are the questioner; that means you don't know the answer. I'm telling you the answer. Drop your preconceptions and just do this the normal way. Here's a full discussion with sample code: http://www.apeth.com/iOSBook/ch19.html#_page_view_controller – matt Jun 21 '14 at 15:12

2 Answers2

1

NSInvocation is for manipulating calls where you don't know the method or number/types of arguments until runtime. Here, the method called is fixed at compile time. You don't need NSInvocation.

If you want to store an action to perform as an object that you can put into an array, you should use blocks.

newacct
  • 119,665
  • 29
  • 163
  • 224
1

Sounds like you want some kind of lazy instantiation.

You can use this helper class

@interface LazyObject : NSObject

@property (copy) id (^block)(void));
@property (readonly) id object;

+ (instancetype)create:(id (^)(void))block;

@end

@implementation LazyObject {
    id _object;
}

+ (instancetype)create:(id (^)(void))block
{
    LazyObject *obj = [[self alloc] init];
    obj.block = block;
    return obj;
}

- (id)object
{
    if (!_object) _object = self.block();
    return _object;
}

@end

NSArray *array = @[[LazyObject create:^id{ return [[SomeClassA alloc] init];}],
                   [LazyObject create:^id{ return [[SomeClassB alloc] init];}]];

SomeClassA *a = [array[0] object];
SomeClassB *b = [array[1] object];

As others said, NSInvocation is not a good solution for your original problem. It is designed to invoke method dynamically. You don't need it for most of the cases.

Bryan Chen
  • 45,816
  • 18
  • 112
  • 143