OK, this was much harder than I had expected…
Basically I am exchanging NSBundle's method that will be invoked by NSLocalizedString(…) by using a category on NSBundle and a technique called isa-swizzeling 
NSBundle+Language.h
#import <Foundation/Foundation.h>
@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end
NSBundle+Language.m
#import "NSBundle+Language.h"
#import <objc/runtime.h>
static const char associatedLanguageBundle=0;
@interface PrivateBundle : NSBundle
@end
@implementation PrivateBundle
-(NSString*)localizedStringForKey:(NSString *)key
                            value:(NSString *)value
                            table:(NSString *)tableName
{
    NSBundle* bundle=objc_getAssociatedObject(self, &associatedLanguageBundle);
    return bundle ? [bundle localizedStringForKey:key
                                            value:value
                                            table:tableName] : [super localizedStringForKey:key
                                                                                      value:value
                                                                                      table:tableName];
}
@end
@implementation NSBundle (Language)
+(void)setLanguage:(NSString*)language
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        object_setClass([NSBundle mainBundle],[PrivateBundle class]);
    });
    objc_setAssociatedObject([NSBundle mainBundle], &associatedLanguageBundle, language ?
                             [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
The AppDelegate will listen for LANGUAGE_WILL_CHANGE notifications, set the language and broadcast a notification LANGUAGE_DID_CHANGE
AppDelegate.m
#import "AppDelegate.h"
#import "NSBundle+Language.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageWillChange:) name:@"LANGUAGE_WILL_CHANGE" object:nil];
    NSString *targetLang = [[NSUserDefaults standardUserDefaults] objectForKey:@"selectedLanguage"];
    [NSBundle setLanguage:targetLang?:@"en"];
    return YES;
}
-(void)languageWillChange:(NSNotification *) noti
{
    NSString *targetLang = [noti object];
    [[NSUserDefaults standardUserDefaults] setObject:targetLang forKey:@"selectedLanguage"];
    [NSBundle setLanguage:targetLang];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"LANGUAGE_DID_CHANGE" object:targetLang];
}
@end
A BaseViewController will post LANGUAGE_WILL_CHANGE and listen for LANGUAGE_DID_CHANGE
BaseViewController.h
#import <UIKit/UIKit.h>
@interface BaseViewController : UIViewController
-(void) languageDidChange;
- (IBAction)switchLanguage:(id)sender;
@end
BaseViewController.m
#import "BaseViewController.h"
@interface BaseViewController ()
@property (weak, nonatomic) IBOutlet UIButton *englishButton;
@property (weak, nonatomic) IBOutlet UIButton *spanishButton;
@end
@implementation BaseViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageDidChangeNotification:) name:@"LANGUAGE_DID_CHANGE" object:nil];
}
- (IBAction)switchLanguage:(id)sender {
    NSString *localString;
    if (self.englishButton == sender) {
        localString = @"en";
    } else if(self.spanishButton == sender){
        localString = @"es";
    }
    if (localString) {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"LANGUAGE_WILL_CHANGE" object:localString];
    }
}
-(void)languageDidChangeNotification:(NSNotification *)notification
{
    [self languageDidChange];
}
-(void)languageDidChange
{
}
@end
Now any view controller that subclasses BaseViewController can implement languageDidChange to call NSLocalizedString.
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [self languageDidChange];
}
-(void)languageDidChange
{
    self.label.text = NSLocalizedString(@"Hello World", nil);
    self.imageView.image = [UIImage imageNamed:NSLocalizedString(@"image.png", nil)];
}
@end
Ad you see, I am simply localising the image name, I added the images en_image.png and es_image.png to the Images asset bundle and map them in the localizable strings
"image.png" = "en_image.png";
and 
"image.png" = "es_image.png";
Result

You'll find this example code here: https://github.com/vikingosegundo/ImmidiateLanguageChange