Я что-то упускаю с ARC? - PullRequest
0 голосов
/ 17 января 2012

Я занимаюсь разработкой крупномасштабного приложения для iOS 5 с использованием ARC в xcode.Система работает хорошо, за исключением случаев, когда я пытаюсь освободить один из моих интерфейсов.Я использую фреймворк под названием WhirlyGlobe для создания трехмерного интерактивного шара в первом контроллере вида.

Когда я переключаю контроллеры вида (между четырьмя, которые у меня есть), я замечаю, что память используется для контроллера видас земным шаром не выпускается.Все остальные контроллеры представления (только с использованием простых представлений и изображений) освобождают свою память нормально - но глобус остается резидентным, или, кажется, так.Когда я возвращаюсь к глобусу, я получаю почти 10-мегабайтный скачок в памяти из-за 1-мегабайтного выделения в glsmLoadTextureLevelBuffer.помочь освободить мои объекты?Я заметил, что мои методы viewDidUnload и dealloc вообще не вызываются, и что единственный способ получить что-либо для запуска - это использовать viewDidDisappear (что, очевидно, не идеально) - см. Ниже:

- (void)clear
{
[[NSNotificationCenter defaultCenter] removeObserver:self];

if (self.layerThread)
{
    [self.layerThread cancel];
    while (!self.layerThread.isFinished)
        [NSThread sleepForTimeInterval:0.001];
}

self.glView = nil;
self.sceneRenderer = nil;

if (theScene)
{
    delete theScene;
    theScene = NULL;
}
self.theView = nil;
self.texGroup = nil;

self.layerThread = nil;
self.earthLayer = nil;
self.vectorLayer = nil;
self.labelLayer = nil;
self.interactLayer = nil;

self.pinchDelegate = nil;
self.panDelegate = nil;
self.tapDelegate = nil;
self.longPressDelegate = nil;
self.rotateDelegate = nil;
}

- (void)viewDidDisappear:(BOOL)animated {
    NSLog(@"dealloc - viewDidDisappear");
    [self clear];
}

Я устанавливаю все, что мне больше не нужно, чтобы ноль.Это лучшая практика?

Код настройки глобуса: [super viewDidLoad];

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

// Set up an OpenGL ES view and renderer
EAGLView *ev = [[EAGLView alloc] initWithFrame:CGRectMake(0, 0, 824, self.view.frame.size.height)];
self.glView = ev;
self.sceneRenderer = [[SceneRendererES1 alloc] init];
UIColor *whiteC = [UIColor whiteColor];
[sceneRenderer setClearColor:whiteC];
glView.renderer = sceneRenderer;
glView.frameInterval = 2;  // 60 fps (2)
[self.view addSubview:glView];
self.view.backgroundColor = [UIColor blackColor];
self.view.opaque = YES;
self.view.autoresizesSubviews = YES;
//glView.frame = self.view.bounds;
glView.frame = CGRectMake(275, GLOBE_HEIGHT_FIX, 768, SCREEN_HEIGHT+STATUS_BAR_HEIGHT); // was 260 x
glView.backgroundColor = [UIColor whiteColor];
self.view.backgroundColor = [UIColor whiteColor]; // red for debug

// Create the textures and geometry, but in the right GL context
[sceneRenderer useContext];

self.texGroup = [[TextureGroup alloc] initWithInfo:[[NSBundle mainBundle] pathForResource:@"bdGlobe_info" ofType:@"plist"]];

// Need an empty scene and view
theScene = new WhirlyGlobe::GlobeScene(4*texGroup.numX,4*texGroup.numY);
self.theView = [[WhirlyGlobeView alloc] init];
[theView setFarPlane:5.0];
[theView setHeightAboveGlobe:GLOBE_HEIGHT_VIEW];
if (globeShouldAnimate) glView.alpha = 1.0;

// Need a layer thread to manage the layers
self.layerThread = [[WhirlyGlobeLayerThread alloc] initWithScene:theScene];

// Earth layer on the bottom
self.earthLayer = [[SphericalEarthLayer alloc] initWithTexGroup:texGroup];
[self.layerThread addLayer:earthLayer];

// Set up the vector layer where all our outlines will go
self.vectorLayer = [[VectorLayer alloc] init];
[self.layerThread addLayer:vectorLayer];

// General purpose label layer.
self.labelLayer = [[LabelLayer alloc] init];
[self.layerThread addLayer:labelLayer];

self.interactLayer = [[InteractionLayer alloc] initWithVectorLayer:self.vectorLayer labelLayer:labelLayer globeView:self.theView
                                                       countryShape:[[NSBundle mainBundle] pathForResource:@"10m_admin_0_map_subunits" ofType:@"shp"]
                                                         oceanShape:[[NSBundle mainBundle] pathForResource:@"10m_geography_marine_polys" ofType:@"shp"]
                                                        regionShape:[[NSBundle mainBundle] pathForResource:@"10m_admin_1_states_provinces_shp" ofType:@"shp"]]; 
self.interactLayer.maxEdgeLen = [self.earthLayer smallestTesselation]/10.0;
[self.layerThread addLayer:interactLayer];

// Give the renderer what it needs
sceneRenderer.scene = theScene;
sceneRenderer.view = theView;

// Wire up the gesture recognizers
self.panDelegate = [PanDelegateFixed panDelegateForView:glView globeView:theView];
self.tapDelegate = [WhirlyGlobeTapDelegate tapDelegateForView:glView globeView:theView];
self.longPressDelegate = [WhirlyGlobeLongPressDelegate longPressDelegateForView:glView globeView:theView];

// Kick off the layer thread
// This will start loading things
[self.layerThread start];

Ответы [ 4 ]

3 голосов
/ 17 января 2012

Для этого вы можете использовать инструмент распределения. Используя снимок кучи, вы можете пометить кучу в различных точках времени жизни вашего приложения и сравнить граф объектов, который представляет текущие выделения в памяти в точке каждого снимка. Это должно помочь вам сузить, что и кем удерживается.

0 голосов
/ 18 января 2012

Я обнаружил проблему после использования снимков кучи (спасибо Марку Адамсу). Оказывается, я не делал пару делегатов слабыми объектами, поэтому они не освобождались при смене контроллера представления. Сильные делегаты по умолчанию остаются резидентами.

Благодаря всем предложениям, они все помогли указать мне правильное направление:)

0 голосов
/ 17 января 2012

убедитесь, что ваш -(void)viewDidDisappear:(BOOL)animated вызван.

если вы используете

[self.view addSubview:yourViewController.view];

и

[yourViewController.view removeFromSuperview];

тогда viewDidDisappear: и viewDidAppear: не будут вызваны

эти обратные вызовы будут вызываться только когда вы используете presentViewController: в IOS 5 или presentModalViewController: и dismissViewControllerAnimated: в IOS 5 или dismissModalViewControllerAnimated: или используйте UINavigationController для представления и отклонения вашего viewController

0 голосов
/ 17 января 2012

Это анекдотично, но МОЖЕТ быть похожая ситуация.

У меня просто была ситуация, когда мои объекты никогда не освобождались, в ARC, даже если к ним обращались статически (например, [SingletonThing instance].thing), потому что пул авто-выпуска не истощал. Причиной этого был странный бесконечный цикл, который работает в своем собственном потоке. Помещение отдельного блока @autorelease для кода.

С другой стороны, даже если один из ваших (или библиотечных) объектов имеет UIView в качестве подпредставления, Я думаю ваш UIViewController никогда не будет viewDidUnload и поэтому никогда не делок. Я должен проверить это опытным путем.

...