Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-25586] : iOS Crash when selecting filtered row in Ti.UI.SearchBar #9677

Merged
merged 13 commits into from
Jan 14, 2018
Merged
84 changes: 56 additions & 28 deletions iphone/Classes/TiUITableView.m
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,11 @@ - (void)setBackgroundColor:(TiColor *)color onTable:(UITableView *)table
[table setOpaque:![[table backgroundColor] isEqual:[UIColor clearColor]]];
}

- (BOOL)isSearchStarted
{
return ([searchController isActive] && searchResultIndexes);
}

- (UITableView *)searchTableView
{
if (_searchTableView == nil) {
Expand Down Expand Up @@ -609,8 +614,9 @@ - (void)replaceData:(NSMutableArray *)data animation:(UITableViewRowAnimation)an
row.parent = section;
}
}

[self reloadDataFromCount:oldCount toCount:newCount animation:animation];
if (![self isSearchStarted]) {
[self reloadDataFromCount:oldCount toCount:newCount animation:animation];
}
}

//Assertions no longer are needed; we ensure that the sections are not nil.
Expand Down Expand Up @@ -730,21 +736,27 @@ - (void)dispatchAction:(TiUITableViewAction *)action
switch (action.type) {
case TiUITableViewActionRowReload: {
TiUITableViewRowProxy *row = (TiUITableViewRowProxy *)action.obj;
NSIndexPath *path = [NSIndexPath indexPathForRow:row.row inSection:row.section.section];
[tableview reloadRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
if (![self isSearchStarted]) {
NSIndexPath *path = [NSIndexPath indexPathForRow:row.row inSection:row.section.section];
[tableview reloadRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
}
break;
}
case TiUITableViewActionUpdateRow: {
TiUITableViewRowProxy *row = (TiUITableViewRowProxy *)action.obj;
[self updateRow:row];
NSIndexPath *path = [NSIndexPath indexPathForRow:row.row inSection:row.section.section];
[tableview reloadRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
if (![self isSearchStarted]) {
NSIndexPath *path = [NSIndexPath indexPathForRow:row.row inSection:row.section.section];
[tableview reloadRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
}
break;
}
case TiUITableViewActionSectionReload: {
TiUITableViewSectionProxy *section = action.obj;
NSIndexSet *path = [NSIndexSet indexSetWithIndex:section.section];
[tableview reloadSections:path withRowAnimation:action.animation];
if (![self isSearchStarted]) {
TiUITableViewSectionProxy *section = action.obj;
NSIndexSet *path = [NSIndexSet indexSetWithIndex:section.section];
[tableview reloadSections:path withRowAnimation:action.animation];
}
break;
}
case TiUITableViewActionInsertRowBefore: {
Expand All @@ -757,8 +769,9 @@ - (void)dispatchAction:(TiUITableViewAction *)action
if (action.animation == UITableViewRowAnimationNone) {
[UIView setAnimationsEnabled:NO];
}

[tableview insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
if (![self isSearchStarted]) {
[tableview insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
}

if (action.animation == UITableViewRowAnimationNone) {
[UIView setAnimationsEnabled:YES];
Expand Down Expand Up @@ -800,8 +813,9 @@ - (void)dispatchAction:(TiUITableViewAction *)action
[addRows addObject:moveRow];
[moveRow release];
}

[tableview deleteRowsAtIndexPaths:removeRows withRowAnimation:UITableViewRowAnimationNone];
if (![self isSearchStarted]) {
[tableview deleteRowsAtIndexPaths:removeRows withRowAnimation:UITableViewRowAnimationNone];
}
}

[sections insertObject:newSection atIndex:newSectionIndex];
Expand All @@ -811,7 +825,9 @@ - (void)dispatchAction:(TiUITableViewAction *)action
//Removing the temporarly saved proxy.
[(TiUITableViewProxy *)[self proxy] forgetProxy:moveRow];
}
[tableview insertSections:[NSIndexSet indexSetWithIndex:newSectionIndex] withRowAnimation:action.animation];
if (![self isSearchStarted]) {
[tableview insertSections:[NSIndexSet indexSetWithIndex:newSectionIndex] withRowAnimation:action.animation];
}

break;
}
Expand All @@ -828,8 +844,9 @@ - (void)dispatchAction:(TiUITableViewAction *)action
if (action.animation == UITableViewRowAnimationNone) {
[UIView setAnimationsEnabled:NO];
}

[tableview insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
if (![self isSearchStarted]) {
[tableview insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
}

if (action.animation == UITableViewRowAnimationNone) {
[UIView setAnimationsEnabled:YES];
Expand Down Expand Up @@ -864,23 +881,28 @@ - (void)dispatchAction:(TiUITableViewAction *)action
[moveRow release];
}
// 1st stage of update: Remove all those nasty old rows.
[tableview deleteRowsAtIndexPaths:removeRows withRowAnimation:UITableViewRowAnimationNone];
if (![self isSearchStarted]) {
[tableview deleteRowsAtIndexPaths:removeRows withRowAnimation:UITableViewRowAnimationNone];
}

// 2nd stage of update: Add in those shiny new rows and update the section.
[sections insertObject:newSection atIndex:newSectionIndex];
[self appendRow:row];
for (TiUITableViewRowProxy *moveRow in addRows) {
[self appendRow:moveRow];
}
[tableview insertSections:[NSIndexSet indexSetWithIndex:newSectionIndex] withRowAnimation:action.animation];

if (![self isSearchStarted]) {
[tableview insertSections:[NSIndexSet indexSetWithIndex:newSectionIndex] withRowAnimation:action.animation];
}
break;
}
case TiUITableViewActionDeleteRow: {
TiUITableViewRowProxy *row = (TiUITableViewRowProxy *)action.obj;
[self deleteRow:row];
NSIndexPath *path = [NSIndexPath indexPathForRow:row.row inSection:row.section.section];
[tableview deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
if (![self isSearchStarted]) {
NSIndexPath *path = [NSIndexPath indexPathForRow:row.row inSection:row.section.section];
[tableview deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
}
break;
}
case TiUITableViewActionSetData: {
Expand All @@ -891,15 +913,19 @@ - (void)dispatchAction:(TiUITableViewAction *)action
case TiUITableViewActionAppendRow: {
TiUITableViewRowProxy *row = (TiUITableViewRowProxy *)action.obj;
[self appendRow:action.obj];
NSIndexPath *path = [NSIndexPath indexPathForRow:row.row inSection:row.section.section];
[tableview insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
if (![self isSearchStarted]) {
NSIndexPath *path = [NSIndexPath indexPathForRow:row.row inSection:row.section.section];
[tableview insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:action.animation];
}
break;
}
case TiUITableViewActionAppendRowWithSection: {
TiUITableViewRowProxy *row = (TiUITableViewRowProxy *)action.obj;
[sections addObject:row.section];
[self appendRow:action.obj];
[tableview insertSections:[NSIndexSet indexSetWithIndex:[sections count] - 1] withRowAnimation:action.animation];
if (![self isSearchStarted]) {
[tableview insertSections:[NSIndexSet indexSetWithIndex:[sections count] - 1] withRowAnimation:action.animation];
}
break;
}
}
Expand Down Expand Up @@ -2087,7 +2113,7 @@ - (void)setContentInsets_:(id)value withObject:(id)props

- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
if ([searchController isActive] && searchResultIndexes) {
if ([self isSearchStarted]) {
int rowCount = 0;
for (NSIndexSet *thisSet in searchResultIndexes) {
rowCount += [thisSet count];
Expand All @@ -2105,7 +2131,7 @@ - (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)sec
- (UITableViewCell *)tableView:(UITableView *)ourTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *index = indexPath;
if ([searchController isActive] && searchResultIndexes) {
if ([self isSearchStarted]) {
index = [self indexPathFromSearchIndex:[indexPath row]];
}

Expand Down Expand Up @@ -2149,7 +2175,9 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)ourTableView
ourTableView.backgroundColor = [UIColor whiteColor];
}

RETURN_IF_SEARCH_TABLE_VIEW(1);
if ([self isSearchStarted]) {
return 1;
}
// One quirk of UITableView is that it really hates having 0 sections. Instead, supply 1 section, no rows.
NSUInteger result = [(TiUITableViewProxy *)[self proxy] sectionCount];
return MAX(1, result);
Expand Down Expand Up @@ -2506,7 +2534,7 @@ - (CGFloat)tableView:(UITableView *)ourTableView estimatedHeightForRowAtIndexPat
- (CGFloat)tableView:(UITableView *)ourTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *index = indexPath;
if ([searchController isActive] && searchResultIndexes) {
if ([self isSearchStarted]) {
index = [self indexPathFromSearchIndex:[indexPath row]];
}

Expand Down
62 changes: 62 additions & 0 deletions tests/Resources/ti.ui.tableview.addontest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Appcelerator Titanium Mobile
* Copyright (c) 2015-Present by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
/* eslint-env mocha */
/* global Ti */
/* eslint no-unused-expressions: "off" */
'use strict';
var should = require('./utilities/assertions');

describe('Titanium.UI.TableView', function () {

it.ios('Delete row (Search Active)', function (finish) {
var win = Ti.UI.createWindow({
backgroundColor: 'blue'
}),
section_0,
searchBar,
tableView,
isFocused;
section_0 = Ti.UI.createTableViewSection({ headerTitle: 'Zero' });
section_0.add(Ti.UI.createTableViewRow({ title: 'Red' }));
section_0.add(Ti.UI.createTableViewRow({ title: 'White' }));
section_0.add(Ti.UI.createTableViewRow({ title: 'Purple' }));

searchBar = Titanium.UI.createSearchBar({showCancel:true});
tableView = Ti.UI.createTableView({
data: [ section_0 ],
search: searchBar
});

isFocused = false;

win.addEventListener('focus', function () {
var error;

if (isFocused) {
return;
}
isFocused = true;

try {
searchBar.setValue('e');
searchBar.focus();
should(tableView.sections[0].rowCount).be.eql(3);
tableView.deleteRow(0);
should(tableView.sections[0].rowCount).be.eql(2);
} catch (err) {
error = err;
}
setTimeout(function () {
win.close();
finish(error);
}, 1000);
});

win.add(tableView);
win.open();
});
});