我正在使用xamarin / monotouch作为ios应用程序。在其中一个搜索屏幕中,当用户键入字符时,我会显示弹出的地址簿中的结果。我有大约5000个联系人,因此我在一个单独的线程中进行过滤,如下所示。
Thread filterThread = new Thread( new ThreadStart( delegate {
// Some ui code
PersonSearchModal.find (findstr);
var personList = PersonSearchModal.getResult ();
// followed by some ui code to update pop up with person list
}));
filterThread.Start ();
以下是搜索5000个联系人的方法
public static void find(string str)
{
lock (filterLock) {
bool next = false;
if (str.Length == 1)
clear ();
if (results.Count == 0) {
next = true;
} else {
PersonSearchResult r = results [results.Count - 1];
if (str.StartsWith (r.findstr, StringComparison.OrdinalIgnoreCase)) {
next = true;
}
}
if (next) {
findNext (str);
} else {
findPrev ();
}
}
}
public static void findNext(string str)
{
if (str.Trim ().Length == 0)
return;
Func<string, bool> filter = s => !String.IsNullOrWhiteSpace(s) && s.StartsWith(str, StringComparison.OrdinalIgnoreCase);
var peoplefrom = results.Count > 0 ? getResult() : people;
var personList = peoplefrom.
Where(p => filter(p.FirstName)
|| filter(p.LastName)
|| p.GetEmails().Select(e => e.Value).Any(filter)).ToList();
var result = new PersonSearchResult ();
result.findstr = str;
result.people = personList;
results.Add (result);
}
它似乎非常像邮件应用中的联系人搜索。但是,当用户快速输入时,应用程序会崩溃,没有任何异常。任何人都可以建议一种更好的方法来安排和同步这些搜索线程。
完整代码
public void filterContact(RectangleF rect, string searchstring)
{
ThreadPool.QueueUserWorkItem ( o => filter (rect, searchstring));
}
void filter(RectangleF rect, string searchstring)
{
lock (this) {
try {
if (searchstring.Trim () == "") {
using (var pool = new NSAutoreleasePool ()) {
pool.InvokeOnMainThread (delegate {
if (DetailViewPopover != null) {
DetailViewPopover.Dismiss (false);
}
return;
});
}
return;
}
string findstr = searchstring;
if (PersonSearchModal.people.Count == 0)
return;
PersonSearchModal.find (findstr);
var personList = PersonSearchModal.getResult ();
using (var pool = new NSAutoreleasePool ()) {
pool.InvokeOnMainThread (delegate {
if (personList.Count == 0) {
if (DetailViewPopover != null)
DetailViewPopover.Dismiss (false);
return;
}
if (DetailViewPopover != null) {
_emailPickerController._searchName = searchstring;
PersonEmailPickerViewControllerSource PEsource = (PersonEmailPickerViewControllerSource)_emailPickerController.TableView.Source;
PEsource.personList = personList;
_emailPickerController.TableView.ReloadData ();
if (!DetailViewPopover.PopoverVisible) {
DetailViewPopover.PopoverContentSize = new SizeF (400, 300);
DetailViewPopover.PresentFromRect (rect, this.View, UIPopoverArrowDirection.Up, true);
}
} else {
_emailPickerController = PersonEmailPickerViewController.GetInstance ();
_emailPickerController._searchName = searchstring;
PersonEmailPickerViewControllerSource PEsource = (PersonEmailPickerViewControllerSource)_emailPickerController.TableView.Source;
PEsource.personList = personList;
_emailPickerController.TableView.ReloadData ();
DetailViewPopover = new UIPopoverController (_emailPickerController);
DetailViewPopover.PopoverContentSize = new SizeF (400, 300);
DetailViewPopover.PresentFromRect (rect, this.View, UIPopoverArrowDirection.Up, true);
}
});
}
} catch (System.Exception) {
}
}
}
答案 0 :(得分:0)
这看起来像是代码中的竞争条件。我的猜测是发生了以下情况:
BeginInvokeOnMainThread
时,主线程将处理相同的数据,这些数据已经从几个线程同时修改(并且可能在主线程也使用数据时被修改),以及你最终从主线程向UI提供垃圾,最终导致崩溃。尝试确保您只是同时运行一个filterThread,并且从不在主线程访问filterThread正在使用的相同数据时。