Доступ к большому файлу в Objective-C, зависает остальная часть программы, пока он делает вещи - PullRequest
0 голосов
/ 23 апреля 2011

Эй.Я немного новичок в Objective-C (для Mac это так), и я пишу приложение, которое будет открывать большие файлы, анализировать их и т. Д.

Проблема в том, что программа выполняет различные задачи,Я хочу обновить индикатор выполнения.Но программа перестает отвечать на запросы до тех пор, пока каждая задача не будет завершена.

Как мне обойти это?

Спасибо.

Ответы [ 4 ]

3 голосов
/ 23 апреля 2011

Если вы выполняете задачу с интенсивным использованием процессора в главном потоке, который отвечает за обновление пользовательского интерфейса и обработку событий клавиатуры / мыши, ваше приложение может перестать отвечать. Используйте один из методов параллельного программирования , доступных программистам Какао, чтобы освободить основной поток от всего, что может его заблокировать.

2 голосов
/ 23 апреля 2011

Вот небольшой пример, который я недавно написал, чтобы выполнить задачу в новом потоке и тем временем обновить пользовательский интерфейс. По сути, просто замените [NSThread sleepForTimeInterval: 0.2] некоторым полезным кодом;)

Заголовок:

#import <Cocoa/Cocoa.h>

@interface ThreadingAppDelegate : NSObject <NSApplicationDelegate> {
@private
    NSWindow *window;
    NSSlider *slider;
    NSProgressIndicator *progresIndicator;
    NSTextField *textField;
    NSButton *button;
    NSButton *panicButton;
    NSThread *aThread;
    int theValue;
}

@property (assign) IBOutlet NSWindow *window;
@property (assign) IBOutlet NSSlider *slider;
@property (assign) IBOutlet NSProgressIndicator *progresIndicator;
@property (assign) IBOutlet NSTextField *textField;
@property (assign) IBOutlet NSButton *button;
@property (assign) IBOutlet NSButton *panicButton;
@property (assign) int theValue;

- (IBAction)startThread:(id)sender;
- (IBAction)stopThread:(id)sender;

- (void)moveStatusBar;
- (void)threadStart;

@end

Реализация:

#import "ThreadingAppDelegate.h"

@implementation ThreadingAppDelegate

@synthesize window;
@synthesize button;
@synthesize panicButton;
@synthesize slider;
@synthesize textField;
@synthesize progresIndicator;
@synthesize theValue;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
}

- (IBAction)startThread:(id)sender
{
    [progresIndicator setDoubleValue:0.0];
    [button setEnabled:NO];
    //[NSThread detachNewThreadSelector:@selector(threadStart) toTarget:self withObject:nil];
    aThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadStart) object:nil];
    [aThread start];
    [panicButton setEnabled:YES];
}

- (IBAction)stopThread:(id)sender
{
    [progresIndicator setDoubleValue:0.0];
    [aThread cancel];
    [aThread release];
    aThread = nil;
    [button setEnabled:YES];
    [panicButton setEnabled:NO];

}

- (void)moveStatusBar
{
    [progresIndicator setDoubleValue:[progresIndicator doubleValue] + 0.5];

    if ([progresIndicator doubleValue] == 100) {
        [button setEnabled:YES];
        [panicButton setEnabled:NO];
    }
}

- (void)threadStart
{

    while([progresIndicator doubleValue] <= 100.0) {
        [self performSelectorOnMainThread:@selector(moveStatusBar) withObject:nil waitUntilDone:NO];
        [NSThread sleepForTimeInterval:0.2];
        if([[NSThread currentThread] isCancelled]) {
            break;
        }
    }

}


@end

Пользовательский интерфейс:

Threaded UI

2 голосов
/ 23 апреля 2011

Вы захотите выполнить свои операции ввода-вывода и анализа файла в фоновом потоке. Есть несколько способов сделать это в Cocoa / Objective-C, наиболее простым из которых является использование Grand Central Dispatch для выполнения действия с dispatch_async() или аналогичной функцией. Есть много вопросов, связанных с выполнением задач с использованием GCD вокруг SO, и здесь и здесь - хорошие места для начала.

Как видно из второй статьи, существуют способы настройки блоков завершения, которые будут выполнять действия пользовательского интерфейса в основном потоке, когда данная операция завершается в потоке диспетчеризации.

1 голос
/ 24 июля 2011

Фоновый поток не всегда правильный ответ.

Если ваша задача связана с ЦП, тогда фоновый поток имеет смысл, но тогда вы должны решить проблемы безопасности потока.

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

См., Например, NSFileHandle readInBackgroundAndNotify: он позволяет ОС заполнить буфер изатем публикует уведомление, когда новые данные доступны.В методе наблюдения вы можете сделать это:

- (void)dataReceived:(NSNotification *)notification
{
    NSDictionary *info = [notification userInfo];
    NSData *newData = [info objectForKey:NSFileHandleNotificationDataItem];
    [allData appendData:newData];
    [progressIndicator setValue:([allData length] / totalFileLength)];
}

В идеале, вы должны анализировать по ходу, а не просто вставлять все новые данные в память, но это может оказаться невозможным для вашей конкретной структуры данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...