LoginSignup
7
8

More than 5 years have passed since last update.

Adobe AIR for iOS の Low memory warning による GC 大量発生を無視する方法

Posted at

今日のバッドノウハウです。

Adobe AIR for iOS では、iOS がアプリケーションに送信する Low memory warning を受けるととりあえずガベージコレクション(GC)を行うようです。
そのため、メモリ使用量が多いとフレームレートが下がり続け、アプリケーションがまともに動作しません。

理想はメモリ使用量を下げることですが、まあそこはとりあえず置いておいて、警告が来ても GC されないようにしたいと思います。この方法を取り入れればフレームレートが下がらずに綺麗にアプリケーションが異常終了してくれるようになります。

詳しく説明すると激しく冗長になるので、とりあえず今回は Adobe Native Extension (ANE) を作ったことがある前提で解説します。

ANE で行うこと

やりたいことは Low memory warning の delegate をオーバーライドして GC を抑制することです。
iOS の AppDelegate の実装は Adobe AIR の中に入ってしまってるため、実装を直接書き換えることは(簡単には)できません。

delegate injection

実装を動的に書き換えるためにリフレクション系の API を使いましょう。

// AirLowMemoryWarningSuppressor.h

#import <UIKit/UIKit.h>
#import "FlashRuntimeExtensions.h"

@interface  AirLowMemoryWarningSuppressor : NSObject <UIApplicationDelegate>
@end


// AirLowMemoryWarningSuppressor.m

@implementation AirLowMemoryWarningSuppressor
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {}
@end


void AirLowMemoryWarningSuppressor_didReceiveMemoryWarning(id self, SEL _cmd, UIApplication* application)
{
    NSLog(@"application did receive memory warning.");
}

void AirLowMemoryWarningSuppressor_injectDelegates(id delegate)                                        
{                                                                                                      
    Class objectClass = object_getClass(delegate);                                                     

    NSString *newClassName = [NSString stringWithFormat:@"CustomLowMemory_%@", NSStringFromClass(objectClass)];
    Class modDelegate = NSClassFromString(newClassName);                                               
    if (modDelegate == nil) {                                                                          
        modDelegate = objc_allocateClassPair(objectClass, [newClassName UTF8String], 0);               
        SEL selectorToOverride = @selector(applicationDidReceiveMemoryWarning:);                       
        Method m = class_getInstanceMethod(objectClass, selectorToOverride);                           
        class_addMethod(modDelegate, selectorToOverride, (IMP)AirLowMemoryWarningSuppressor_didReceiveMemoryWarning, method_getTypeEncoding(m));
        objc_registerClassPair(modDelegate);                                                           
    }                                                                                                  
    object_setClass(delegate, modDelegate);                                                            
} 
void AirLowMemoryWarningSuppressor_initializeContext(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet)
{
    AirLowMemoryWarningSuppressor_injectDelegates([[UIApplication sharedApplication] delegate]);
    *numFunctionsToTest = 0;
}

void AirLowMemoryWarningSuppressor_finalizeContext(FREContext ctx) { }

void LowMemoryInitializeExtension(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet)
{
    *extDataToSet = NULL;
    *ctxInitializerToSet = &AirLowMemoryWarningSuppressor_initializeContext;
    *ctxFinalizerToSet = &AirLowMemoryWarningSuppressor_finalizeContext;
}

void LowMemoryFinalizeExtension(void *extData) { }

やってること

  • AirLowMemoryWarningSuppressor extends UIApplicationDelegate クラスを作る
  • そこに applicationDidReceiveMemoryWarning の delegate を空っぽ実装する
  • ANE Context の初期化時に [[UIApplication sharedApplication] delegate] で現状の delegate のインスタンスを取得
  • delegate のクラスを取得
  • クラスを継承して新しいクラスを作る
  • そのクラスの applicationDidReceiveMemoryWarning に AirLowMemoryWarningSuppressor_didReceiveMemoryWarning の実装をオーバーライドする(これしないと継承後のクラスのメソッドとして上書きできない)
  • 現在の delegate インスタンスのクラスを新しいクラスとして認識させる

これで、Adobe AIR の delegate を無理やり自作クラスのインスタンスってことにできます。

7
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8