Tuesday, January 29, 2013

Нереально лагает табличка UITableView, делал делал вот по этому уроку.

http://www.imaladec.com/forum/index.php?/topic/659-tableview-%D1%82%D0%BE%D1%80%D0%BC%D0%BE%D0%B7%D0%B8%D1%82/page__p__4136__hl__%D1%82%D0%BE%D1%80%D0%BC%D0%BE%D0%B7%D0%B8%D1%82__fromsearch__1#entry4136

Отправлено 25 Июль 2012 - 16:03

Нереально лагает табличка, делал делал вот по этому уроку.
Не знаю в чем дело, единственное, я массивы собираю на стороне из SQLite, возможно в этом дело? :huh: 

// Table
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
   
return [[self.refreshProtocol returnDataForTable] count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
   
NSArray *curent = [self curent:section];
   
return [curent count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
   
return [[[self.refreshProtocol returnDataForTable] allKeys] objectAtIndex:section];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   
static NSString *CellIdentifier = @"Cell";
   
   
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
   
if (cell == nil) {
        cell
= [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier
:CellIdentifier] autorelease];
   
}
   
   
NSArray *curent = [self curent:indexPath.section];
    cell
.textLabel.text = [curent objectAtIndex:indexPath.row];
   
   
return cell;
}

- (NSArray *)curent:(NSInteger)index {
   
NSArray *keys = [[self.refreshProtocol returnDataForTable] allKeys];
   
NSString *curentKey = [keys objectAtIndex:index];
   
NSArray *curent = [[self.refreshProtocol returnDataForTable] objectForKey:curentKey];
   
return curent;
}


Полный код класса: .h.m 
0

#2Пользователь офлайн   Nikitich 

  • Продвинутый пользователь
  • PipPipPip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:195
  • Регистрация:31 Май 12
  • Моя OS:10.7.4
  • Мой Гаджет:iPhone 3G, 3GS, 4, iPad, iPad 2
  • Моя iOS:4.0-5.1.1
  • Мой xCode:4.3.2

Отправлено 25 Июль 2012 - 18:43

Да что-то слишком много call-ов, долго строится ячейка. Таблица не все ячейки сразу строит а по мере скрола (чтобы память не забивать), те что "за экраном" дестроит и строит по новой когда до них доскролишь.
Поэтому этот метод лучше не нагружать.

есть пара вариантов 
1. сформируйте сначала массив данных и из него заполняйте таблицу
2. если не большая таблица, можно сразу сформировать массив ячеек (но они все в памяти будут соответствено) 
2

#3Пользователь офлайн   Shrugged 

  • Новичок
  • Pip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:9
  • Регистрация:25 Июль 12
  • Моя OS:last
  • Мой Гаджет:iPhone 4s
  • Моя iOS:last
  • Мой xCode:last

Отправлено 25 Июль 2012 - 19:55

Просмотр сообщенияNikitich (25 Июль 2012 - 18:43) писал:

1. сформируйте сначала массив данных и из него заполняйте таблицу

Я пробовал передавать словарь с данными, прописал в @interface, присвоил в viewDidLoad, но приложение стало вылетать при попытке загрузить еще ячейки
// Table
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
   
return [tableData count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
   
NSArray *curent = [self curent:section];
   
return [curent count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
   
return [[tableData allKeys] objectAtIndex:section];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   
static NSString *CellIdentifier = @"Cell";
   
   
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
   
if (cell == nil) {
        cell
= [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier
:CellIdentifier] autorelease];
   
}
 
   
NSArray *curent = [self curent:indexPath.section];
    cell
.textLabel.text = [curent objectAtIndex:indexPath.row];
   
   
return cell;
}

- (NSArray *)curent:(NSInteger)index {
   
NSArray *keys = [tableData allKeys];
   
NSString *curentKey = [keys objectAtIndex:index];
   
NSArray *curent = [tableData objectForKey:curentKey];
   
return curent;
}


Насколько я могу судить, оно стопорится на:
  NSArray *curent = [self curent:indexPath.section];



Просмотр сообщенияNikitich (25 Июль 2012 - 18:43) писал:

2. если не большая таблица, можно сразу сформировать массив ячеек (но они все в памяти будут соответствено)

А не расскажете, как такое реализовывается? :rolleyes: 
0

#4Пользователь офлайн   Nikitich 

  • Продвинутый пользователь
  • PipPipPip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:195
  • Регистрация:31 Май 12
  • Моя OS:10.7.4
  • Мой Гаджет:iPhone 3G, 3GS, 4, iPad, iPad 2
  • Моя iOS:4.0-5.1.1
  • Мой xCode:4.3.2

Отправлено 25 Июль 2012 - 20:39

Цитата

Я попробовал один раз передавать словарь с данными, прописал в @interface, присвоил в viewDidLoad, но приложение стало вылетать при попытке загрузить еще ячейки (код ниже)


Значит вы его не проиниализировали myArray = [[NSArray alloc] initWithArray:..]; а просто присвоили myArray = ... илиmyArray = [NSArray arrayWithArray:...]; Вот он и дестройнулся и таблице неоткуда было брать данные. 

Я предлагаю сначала сформировать массив из массивов вида:

MyArray:
абстрактно 

  item1
      item1
      item2
     
...
item2
      item1
      item2
     
...

И в методе cellForRowAtIndexPath делать следующее:

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   
static NSString *CellIdentifier = @"Cell";
   
   
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
   
if (cell == nil) {
        cell
= [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier
:CellIdentifier] autorelease];
   
}
   
    cell
.textLabel.text = [[myArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
   
   
return cell;
}


Массив ячеек я имел в виду массив уже сформированых ячеек. Чтобы не формировать их в cellForRowAtIndexPath
Позже напишу если понадобится 
2

#5Пользователь офлайн   Shrugged 

  • Новичок
  • Pip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:9
  • Регистрация:25 Июль 12
  • Моя OS:last
  • Мой Гаджет:iPhone 4s
  • Моя iOS:last
  • Мой xCode:last

Отправлено 25 Июль 2012 - 20:57

Просмотр сообщенияNikitich (25 Июль 2012 - 20:39) писал:

Значит вы его не проиниализировали myArray = [[NSArray alloc] initWithArray:..]; а просто присвоили myArray = ... или myArray = [NSArray arrayWithArray:...]; Вот он и дестройнулся и таблице неоткуда было брать данные. 

Вы чертовски правы, я забыл проинициализировать
Теперь все работает, работает плавненько. Спасибо! :) 

Просмотр сообщенияNikitich (25 Июль 2012 - 20:39) писал:

Массив ячеек я имел в виду массив уже сформированых ячеек. Чтобы не формировать их в cellForRowAtIndexPath
Позже напишу если понадобится

Очень бы хотелось увидеть альтернативное решение :rolleyes: 
0

#6Пользователь офлайн   terr 

  • Продвинутый пользователь
  • PipPipPip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:60
  • Регистрация:12 Март 12
  • ГородVladivostok
  • Моя OS:10.8
  • Мой Гаджет:IPad2, Iphone3G, Mac mini, macbook pro late2011
  • Моя iOS:5.0
  • Мой xCode:4.4

Отправлено 10 Сентябрь 2012 - 06:46

Мне бы тоже хотелось увидеть... дело в том, что у меня таблица с фиксированным числом строк, но строки кастомные, т.е. каждая строка - это некий набор вьюшек - лейблов и кнопок. При прокрутке всё это дело лагает ужасно. Хочу нереальной оптимизации =) 
0

#7Пользователь офлайн   armatura 

  • Продвинутый пользователь
  • PipPipPip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:137
  • Регистрация:30 Ноябрь 11
  • Моя OS:Lion 10.7.4
  • Мой Гаджет:iPad
  • Моя iOS:5.0.1
  • Мой xCode:4.2.1

Отправлено 10 Сентябрь 2012 - 10:32

а какой у Вас xCode? Запустите диагностику и посмотрите, скорее всего утечки памяти. Начиная с 4.3 до 4.4 все ревью текут, сами по себе.. 
Куда пропали кнопки с телефонов?!
0

#8Пользователь офлайн   Nikitich 

  • Продвинутый пользователь
  • PipPipPip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:195
  • Регистрация:31 Май 12
  • Моя OS:10.7.4
  • Мой Гаджет:iPhone 3G, 3GS, 4, iPad, iPad 2
  • Моя iOS:4.0-5.1.1
  • Мой xCode:4.3.2

Отправлено 10 Сентябрь 2012 - 12:01

Да нет. Утечки тут скорее всего не причем. Просто ячейки долго формируются. 

Альтернативный вариант. Ячейки сначала формируются и кладуться в массив. А потом из уже сформированых ячеек строится таблица.
Но следует учитывать что в этом случае все ячейки будут лежать в памяти, это не совсем правильно, поэтому не стоит строить таблицу из 1000 ячеек таким способом. 

Обычно есть массив с данными по ячейкам по которму строится каждая отдельная ячейка в cellForRowAtIndexPath. Пусть будет cellsDataArray. И в нем будут содержаться строки.
Но строить ячейки будем не в cellForRowAtIndexPath, а в viewDidLoad 

Итак в .h файле объявили массив ячеек 
  NSArray *cellsArray;


Далее в .m файле во вьюдидлоад формируем массив ячеек. 

  - (void)viewDidLoad
{
   
[super viewDidLoad];

   
NSMutableArray *cells = [NSMutableArray arrayWithCapacity:[cellsDataArray count]];    //Временный мьютабл массив

   
for (int i=0;i<[cellsDataArray count];i++)
   
{
       
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; //reuseIdentifier нам не нужен поскольку мы не будем юзать dequeueReusableCellWithIdentifier
        cell
.textLabel.text = [cellsDataArray objectAtIndex:i];
       
[cells addObject:cell];
   
}
   
    cellsArray
= [[NSArray alloc] initWithArray:cells]; //Инициализируем наш массив ячеек

}



Массив сформирован и теперь в cellForRowAtIndexPath нам останется вернуть только элемент этого массива согласноindexPath

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   
return [cellsArray objectAtIndex:indexPath.row];
}


В общем как-то так. Я не сильно силен в объяснениях, если что будет не понятно, слеплю проект примера как будет время 
0

#9Пользователь офлайн   AllDmeat 

  • Продвинутый пользователь
  • PipPipPip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:36
  • Регистрация:23 Сентябрь 12
  • Моя OS:Windows 7
  • Мой Гаджет:iPhone 4
  • Моя iOS:5.0.1
  • Мой xCode:4.5

Отправлено 27 Сентябрь 2012 - 15:44

Спасибо, очень помогло. 
0

#10Пользователь офлайн   d3n5a 

  • Продвинутый пользователь
  • PipPipPip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:109
  • Регистрация:19 Январь 12
  • Моя OS:lion
  • Мой Гаджет:nokia
  • Моя iOS:2.1
  • Мой xCode:а что это?

Отправлено 27 Сентябрь 2012 - 22:32

А что будет, если в таблице должно быть 100500 записей? Это создаются 100500 ячеек и ложатся в массив? И что будет с памятью. Не гоните.

Таблица ж специально сделана так, что ячейки реюзались. Они создаются только для видимой области и реюзаются. 
Посмотрите видео Understanding iOS View Compositing 
0

#11Пользователь офлайн   Nikitich 

  • Продвинутый пользователь
  • PipPipPip
  • Вставить ник
  • Цитировать
  • Раскрыть информацию
  • Группа:Пользователи
  • Сообщений:195
  • Регистрация:31 Май 12
  • Моя OS:10.7.4
  • Мой Гаджет:iPhone 3G, 3GS, 4, iPad, iPad 2
  • Моя iOS:4.0-5.1.1
  • Мой xCode:4.3.2

Отправлено 28 Сентябрь 2012 - 10:20

Эм... я ж писал что это вариант для малого количества ячеек и не стоит так делать для 100500 ячеек. Читайте хоть. 

Для 100500 ячеек конечно надо реюзабл использовать, никто не спорит. Но тогда если картинки брать с флешки таблица заметно притормаживает. Нужно придумывать какой-то механизм предварительной их загрузки/выгрузки из памяти частями.
0

No comments:

Post a Comment