2

ファイルの読み取り状況を示すプログレスバーを作成したいのですが。変数_progressを含むC++クラスReaderを使用してファイルを読み取りました。

ReaderクラスにObjCコードを記述せずに、進行状況バーをreader._progressの値で更新するようにCocoaに指示するにはどうすればよいですか?

どんな助けでもいただければ幸いです。

ProgressController *pc = [[ProgressController alloc] init];
[pc showWindow:sender];


// Create the block that we wish to run on a different thread
void (^progressBlock)(void);
progressBlock = ^{
    [pc.pi setDoubleValue:0.0];
    [pc.pi startAnimation:sender];

    Reader reader("/path/to/myfile.txt");
    reader.read();

    while (reader._progress < 100.)
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            [pc.pi setDoubleValue:reader._progress];
            [pc.pi setNeedsDisplay:YES];
        });
    }
}; // end of progressBlock

// Finally, run the block on a different thread
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, progressBlock);

これが私の2回目の試みです。

リーダーコード:

class PDBReader
{
public:
Reader(const char *filename);
Reader(string filename);
~Reader();

int read();

string _filename;
float _progress;

void setCallback(void (^cb)(double))
{
    if (_cb)
    {
        Block_release(_cb);
        _cb = Block_copy(cb);
    }
}
void (^_cb)(double);

protected:
private:
};



int Reader::read()
{
string buffer;
unsigned atomid = 0;
ifstream file;
file.open(_filename.c_str(), ifstream::in);

if (!file.is_open())
{
    return IOERROR;
}

file.seekg(0, ios_base::end);
float eof = (float) file.tellg();
file.seekg(0, ios_base::beg);

while (getline(file, buffer))
{
    _progress = (float) file.tellg() / eof * 100.;
    if (_cb)
    {
        _cb(_progress);
    }
        // some more parsing here...
    }
file.close();
return SUCCESS;
}

PDBReader::~PDBReader()
{
if (_cb)
{
    Block_release(_cb);
}
}

そしてココアの部分:

-(IBAction) test:(id) sender
{
ProgressController *pc = [[ProgressController alloc] init];
[pc showWindow:sender];

Reader reader("test.txt");

reader.setCallback(^(double progress) 
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [pc.pi setDoubleValue:progress]; 
        [pc.pi setNeedsDisplay:YES];
    });
});

reader.read();
}

ご協力いただきありがとうございます。

4

2 に答える 2

7

ReaderにObjective-Cコードを含めたくないからといって、外部からしか観察できないわけではありません。渡された関数ポインタを介してC関数を呼び出すことができます。より一般的なファンクター(関数オブジェクト)メカニズムを使用できます。それもブロックを取ることができます。

while (reader._progress < 100.)あなたは間違いなくそのループをしたくありません。それはビジーループです。コンピューターで可能な限り高速に進行状況を更新します。CPUコアを100%の使用率でペグします。実際、タスクを実行できるよりも速くメインディスパッチキューにキューイングする可能性があります。

Readerがメンバーを更新したときにのみ進行状況インジケーターを更新_progressする必要があります。これには、Readerクラスからの何らかの協力が必要になります。

于 2012-04-04T17:02:07.000 に答える
0

ついに!!!!!

キューに入れない場合はうまく機能します。

ProgressController *pc = [[ProgressController alloc] init];
[pc showWindow:sender];
[pc.pi setUsesThreadedAnimation:YES];

Reader reader("test.txt");  
reader.setCallback(^(double progress) 
{
    [pc.pi setDoubleValue:progress]; 
    [pc.pi setNeedsDisplay:YES];
});

reader.read();

しかし、なぜ「メインスレッドをブロックするので、これは悪い」と言うのでしょうか? 基本的に私のプログラムは、他のことをする前にファイルが読み込まれるのを待たなければならないからです。ここで見逃している基本的な最適化はありますか?

どうもありがとうございました。

于 2012-04-24T09:32:58.470 に答える