Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create custom dynamic classes in objective-c

In my application i have an UIViewController that i uses a lot of UIAlertView to ask things to the user.

Because i need the response of each UIAlertView i have made my controller a delegate of UIAlertViewDelegate, this works fine but after 7 UIAlertView's i`m trying to find a better way to use delegates.

In java i know that i can create inline classes for a single purpose, like in this question: Java - inline class definition

What i want to know is: Is there a way to create a class to be delegate dynamically? to achieve something like this

id<UIAlertViewDelegate> myCustomClass = @class {
    my class code goes here
}

UIAlertView* alertView;
alertView = [[UIAlertView alloc] initWithTitle:@"Title"
                                       message:@"Message"
                                      delegate:myCustomClass
                             cancelButtonTitle:@"No"
                             otherButtonTitles:@"OK", @"Sure", @"Maybe", nil] ];    
[alertView show];
like image 892
Nicos Karalis Avatar asked Oct 01 '12 13:10

Nicos Karalis


2 Answers

No - there are no 'inline classes' in Objective-C. With that said, you can create custom objects at run-time with objective-c, which is a little bit more involved, but I'd be willing to share some code to do what you are saying.

Here is an example of that:

NSObject+Subclass.h

#import <objc/runtime.h>

typedef struct selBlockPair { SEL aSEL; id (^__unsafe_unretained aBlock)(id, ...); } selBlockPair;
#define NIL_PAIR ((struct selBlockPair) { 0, 0 })
#define PAIR_LIST (struct selBlockPair [])
#define BLOCK_CAST (id (^)(id, ...))

@interface NSObject (subclass)

+(Class) newSubclassNamed:(NSString *) name
            protocols:(Protocol **) protos
                 impls:(selBlockPair *) impls;

@end

NSObject+Subclass.m

@implementation NSObject (subclass)

+(Class) newSubclassNamed:(NSString *)name
             protocols:(Protocol **)protos
                 impls:(selBlockPair *)impls
{
    if (name == nil)
    {
        // basically create a random name
        name = [NSString stringWithFormat:@"%s_%i_%i", class_getName(self), arc4random(), arc4random()];
    }

    // allocated a new class as a subclass of self (so I could use this on a NSArray if I wanted)
    Class newClass = objc_allocateClassPair(self, [name UTF8String], 0);

    // add all of the protocols untill we hit null
    while (protos && *protos != NULL)
    {
        class_addProtocol(newClass, *protos);
        protos++;
    }

    // add all the impls till we hit null
    while (impls && impls->aSEL)
    {
        class_addMethod(newClass, impls->aSEL, imp_implementationWithBlock(impls->aBlock), "@@:*");
        impls++;
    }

    // register our class pair
    objc_registerClassPair(newClass);

    return newClass;
}

@end

Example Usage:

int main()
{
    @autoreleasepool {
        __strong Class newClass = [NSString newSubclassNamed:@"MyCustomString" protocols:NULL impls: PAIR_LIST {
            @selector(description),
            BLOCK_CAST ^id (id self) {
                return @"testing";
            },
            NIL_PAIR
        }];

        NSString *someString = [newClass new];
        NSLog(@"%@", someString);
    }
}

Output:

2012-10-01 10:07:33.609 TestProj[54428:303] testing
like image 83
Richard J. Ross III Avatar answered Oct 20 '22 04:10

Richard J. Ross III


This type of Java anonymous inner class is not something that is supported in Objective-C. If you want to respond to the delegates individually, I good way is to experiment with blocks.

Unfortunately, Apple has not added blocks into UIAlertViews, but you can implement them yourself. A bunch of people have done this online. Take a look here: http://blog.mugunthkumar.com/coding/ios-code-block-based-uialertview-and-uiactionsheet/ or https://github.com/MugunthKumar/UIKitCategoryAdditions .

The basic idea is that you can create a subclass (or a category if using associated objects), that will be its own delegate and tell its own delegate to call a block you pass in

like image 37
James Paolantonio Avatar answered Oct 20 '22 03:10

James Paolantonio