2016-10-09 5 views
2

Используя среду выполнения Objective C, я пытаюсь создать AppDelegate для моего приложения iOS во время выполнения. Это просто для исследовательских целей, у меня нет намерения отправить это.Создайте класс UIApplicationDelegate во время выполнения

Мои шаги до сих пор являются:

  • Создать класс во время выполнения называется AppDelegate.
  • Добавьте переменную экземпляра, которая называется _window.
  • Добавить свойство window, который использует переменную экземпляра в качестве переменной основы и использовать две функции C, как получения и установки.
  • Добавить метод для селектора application:didFinishLaunchingWithOptions: с реализацией в C, которая возвращает YES. На этом этапе класс реализует протокол UIApplicationDelegate.
  • Зарегистрируйте класс со временем выполнения.

Однако, когда я запускаю программу на подключенном iPhone, экран остается черным, несмотря на то, что программа на самом деле не сбой. Отладчик показывает, что мои реализации вызываются. Следуя документации, ОС сначала проверяет, является ли мое свойство windownil (оно есть), а затем создает сам UIWindow и использует мой сеттер для назначения UIWindow моему экземпляру делегата.

Когда я обращаюсь к этому окну, он выглядит полностью функциональным: он имеет обычные границы (NSRect: Height = 667; Width = 375; X = 0; Y = 0;), и мой пользовательский ViewController запускается, viewDidLoad ,

Может кто-нибудь помочь мне узнать, почему экран остается черным?

Звонки на [self.window makeKeyAndVisible] не работают, экран остается черным. Если я создаю окно самостоятельно в application:didFinishLaunchingWithOptions: и назначу rootViewController предыдущего UIWindow, это сработает. Так что определенно UIWindow в моем делегате так или иначе сломался.

Вот код, я использую:

#import <UIKit/UIKit.h> 
#import <objc/runtime.h> 
#import <stdio.h> 


id getter(id self, SEL _cmd) { 
    Ivar ivar = class_getInstanceVariable(objc_getClass("AppDelegate"), "_window"); 
    id var = object_getIvar(self, ivar); 
    printf("is nil: %s\n", var == nil ? "true" : "false"); 
    if (var != nil) { 
     printf("%s\n", [[NSString stringWithFormat:@"%@", CGRectCreateDictionaryRepresentation(((UIWindow *) var).bounds)] UTF8String]); 
    } 
    return object_getIvar(self, ivar); 
} 

void setter(id self, SEL _cmd, id new) { 
    printf("setter...\n"); 
    Ivar ivar = class_getInstanceVariable(objc_getClass("AppDelegate"), "_window"); 
    object_setIvar(self, ivar, new); 
} 

BOOL didFinishLaunching(id self, SEL _cmd, id launchOptions) { 
    printf("didFinishLaunching called\n"); 
    return YES; 
} 


int main(int argc, char * argv[]) { 
    @autoreleasepool { 
     Class delegate = objc_allocateClassPair([NSObject class], "AppDelegate", 0); 
     class_addIvar(delegate, "_window", sizeof(UIWindow *), rint(log2(sizeof(UIWindow *))), @encode(UIWindow *)); 

     objc_property_attribute_t type = { "T", "@\"UIWindow\"" }; 
     objc_property_attribute_t strength = { "&", "" }; 
     objc_property_attribute_t atomic = { "N", "" }; 
     objc_property_attribute_t backingVar = { "V", "_window" }; 
     objc_property_attribute_t attrs[] = { type, strength, atomic, backingVar }; 
     class_addProperty(delegate, "window", attrs, 4); 

     class_addMethod(delegate, @selector(window), (IMP) getter, "@@:"); 

     class_addMethod(delegate, @selector(setWindow:), (IMP) setter, "[email protected]:@"); 

     class_addMethod(delegate, @selector(application:didFinishLaunchingWithOptions:), 
         (IMP) didFinishLaunching, "[email protected]:@"); 
     objc_registerClassPair(delegate); 

     return UIApplicationMain(argc, argv, nil, @"AppDelegate"); 
    } 
} 

И это выход стандартный вывод:

is nil: true 
setter... 
didFinishLaunching called 
is nil: false 
{ 
    Height = 667; 
    Width = 375; 
    X = 0; 
    Y = 0; 
} 
is nil: false 
{ 
    Height = 667; 
    Width = 375; 
    X = 0; 
    Y = 0; 
} 
ViewController.viewDidLoad() called 
is nil: false 
{ 
    Height = 667; 
    Width = 375; 
    X = 0; 
    Y = 0; 
} 
+0

Где код, который фактически создает окно и контроллер? Это обычно делается в методе 'didFinishLaunching'. – rmaddy

+0

Не с раскадровки. UIApplication извлекает свойство окна делегата и, если оно равно nil, создает окно самостоятельно и устанавливает его в это свойство. Подробнее здесь: http://stackoverflow.com/a/16446971/4351927 – Longhanks

+0

Вы ничего не сказали об использовании раскадровки. – rmaddy

ответ

2

Найдено вопрос: ARC выпускала мой UIWindow.

Изменение сеттер в

void setter(id self, SEL _cmd, id new) { 
    Ivar ivar = class_getInstanceVariable(object_getClass(self), "_window"); 
    id old = object_getIvar(self, ivar); 
    if (![old isEqual: new]) { 
     if(old != nil) { 
      objc_msgSend(old, sel_getUid("release")); 
     } 
     object_setIvar(self, ivar, new); 
     objc_msgSend(new, sel_getUid("retain")); 
    } 
} 

это исправлено.

Смежные вопросы