Массив проблем с утечкой памяти YAJL

#objective-c #memory-management #uiview #nsarray #yajl

#objective-c #управление памятью #uiview #nsarray #yajl

Вопрос:

Я пытаюсь извлекать данные JSON каждые 2 секунды и передавать их в другой класс для обработки, все работает нормально, но в приведенном ниже коде, похоже, есть утечки памяти (из инструментов), но я не могу понять, что не так и как я могу исправить, может кто-нибудь посоветовать, пожалуйста???

* Обновлено с полной логикой, и похоже, что массив, который передается в основной метод, протекает, и инструменты ошибочно сообщают об этом как об утечке YAJL..(ты не очень уверен)*

     @property (nonatomic,retain,readwrite) NSMutableArray *deviceListArray;


    - (void)viewDidLoad
    {
        [super viewDidLoad];
        deviceListArray=[[NSMutableArray alloc]init];
        [self init];
        TestClass *initiateData = [GetData alloc]init];
        [initiateData startTimer];
        [initiateData release];
    }

    - (id) init{
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(receiveDeviceListNotification:) 
                                                     name:@"devicelist"
                                                   object:nil];
         }

    - (void) receiveDeviceListNotification:(NSNotification *) notification{
            deviceListArray=[notification object];
            [deviceListTable reloadData];

    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

        return [deviceListArray count];
    }

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        [deviceListArray retain]; //CRASHES WITHOUT RETAIN specified here
        static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        cell.textLabel.textColor = [UIColor redColor]; 
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
        }
        [cell.textLabel setText:[deviceListArray objectAtIndex:indexPath.row]]; //CRASHES if i remove the retain on devicelistarray
        return cell;
    }


    @class TestClass;

    @implementation TestClass

    - (void)startTimer:(NSString *)timerstring
    {
        if(timerstring ==@"StartNow")
        {
            NSLog(@"Timer started");
            [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(TestMethod:) userInfo:nil repeats:YES];
        }
        else{
            NSLog(@"string not received");
        }
    }

    -(void)TestMethod:(NSTimer *)Timer {            
        NSTimeInterval timeNow= [NSDate timeIntervalSinceReferenceDate];
        NSData  *JSONData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.example/data.json"]];

        NSArray *testArray=[JSONData yajl_JSON]; //MEMORY LEAK HERE


        if(testArray==nil)
        {
            NSLog(@"Array is nil");
        }
        else
        {
            NSArray *arrayNumberOne=[[testArray valueForKey:@"devicelist"]objectAtIndex:0];
            NSArray *arrayNumberTwo=[testArray valueForKey:@"arrayNumberTwo"];
            NSArray *arrayNumberThree=[testArray valueForKey:@"arrayNumberThree"];        
            float dowloadY=[[arrayNumberTwo objectAtIndex:0]floatValue];
            float uploadY=[[arrayNumberThree objectAtIndex:0]floatValue];

            NSDictionary  *newarrayNumberTwoData=  [NSDictionary dictionaryWithObjectsAndKeys:
                [NSDecimalNumber numberWithInt:timeNow], [NSNumber numberWithInt:0], 
                [NSDecimalNumber numberWithFloat:dowloadY], [NSNumber numberWithInt:1],nil
            ] ;

            NSDictionary  *newarrayNumberThreeData=  [NSDictionary dictionaryWithObjectsAndKeys:
                [NSDecimalNumber numberWithInt:timeNow], [NSNumber numberWithInt:0],
                [NSDecimalNumber numberWithFloat:uploadY], [NSNumber numberWithInt:1],nil
            ] ;

            [[NSNotificationCenter defaultCenter] postNotificationName:@"devicelist" object:arrayNumberOne];

            [[NSNotificationCenter defaultCenter] postNotificationName:@"TestData2" object:newarrayNumberTwoData];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"TestData3" object:newarrayNumberThreeData];
        }
    }

    -(void) dealloc{
        [super dealloc];
    }

    @end
  

Журнал утечек памяти из инструментов приведен ниже

 Утечка объекта # Размер адреса, ответственный за библиотеку, ответственный за фрейм
 __NSArrayM,569 < несколько> 17,78 КБ MYTESTAPP3 -[YAJLDocument parserDidStartArray:]
 Malloc 80 байт,480 < кратных> 37,50 КБ MYTESTAPP3 -[YAJLDocument PARSER_DIDSTARTARRAY:]
 NSCFString,397 < кратных> 11,44 КБ Foundation -[nsplaceholderstr initWithBytes:длина:кодировка:]
 NSCFString, 0x4c1dac0 32 байта Foundation -[nsplaceholderstr initWithBytes:длина:кодировка:]

Комментарии:

1. Существует два yajl — один на C (который также имеет привязки к Haskell) и один на Ruby. Итак, я также пометил этот ruby.

2. Что такое Instaruments (или инструменты) — можете ли вы предоставить ссылку на него?

3. @Andrew Grimm я использую «Инструменты» из ссылки Xcode: developer.apple.com/technologies/tools

4. Как вы объявляете arrayNumberOne,arrayNumberTwo, arrayNumberThree?

5. @Nathan S локально, (sry, я пропустил это раньше). Я отредактировал вопрос с правильным объявлением

Ответ №1:

Ну, это выглядит просто. Сначала вы определили свои jsonData как ‘retain’ вместо ‘assign’, а затем при вызове метода тестирования в последующих запусках происходит утечка предыдущего, поскольку вы не используете установщик, а обращаетесь к переменной экземпляра напрямую. Если вам не нужны jsonData ни в каком другом месте, кроме этого метода, просто определите его как локальную переменную и не делайте ничего особенного — он автоматически освобождается. И второе — то же самое происходит с testArray. Опять же, если вам это не нужно в других местах, то определите как локальную переменную, и если вам это нужно, то используйте установщик.

Обновление: Теперь у вас аналогичная проблема, только на этот раз с deviceListArray. Сначала инициализируйте его следующим образом:

 self.deviceListArray=[NSMutableArray array];
  

затем, каждый раз, когда вы хотите назначить, используйте это:

self.deviceListArray = newObject;

при освобождении выполните

[Выпуск deviceListArray];

Комментарии:

1. я внес поправки на основе ваших комментариев, но NSArray «testArray» все еще протекает в соответствии с инструментами

2. Теперь это больше похоже на ошибку YAJL. Если вы можете опубликовать код где-нибудь, я могу дать его посмотреть. Я посмотрел на github.com/gabriel/yajl-objc/blob/master/Classes/YAJLDocument.m , но не увидел ничего очевидного.

3. я обновил полную логику, и похоже, что devicearray, который передается в основной метод, вызывает утечку. если я удалю [devicelistarray retail] из-за (UITableViewCell *) метода TableView: (UITableView *) TableView cellForRowAtIndexPath: (NSIndexPath *)indexPath, он потерпел крах и сохранится, возможно, причиной утечки .. можете ли вы, пожалуйста, посоветовать, как исправить? tks