UIImageViewサブビューを持つUIViewがあります。 UIをブロックせずに、UIImageViewに画像をロードする必要があります。ブロッキング呼び出しはUIImage imageNamed:
のようです。この問題を解決したと私が思ったのは次のとおりです。
-(void)updateImageViewContent {
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage * img = [UIImage imageNamed:@"background.jpg"];
dispatch_sync(dispatch_get_main_queue(), ^{
[[self imageView] setImage:img];
});
});
}
画像は小さい(150x100)。
ただし、画像の読み込み時にはUIは引き続きブロックされます。私は何が欠けていますか?
この動作を示す小さなコードサンプルを次に示します。
UIImageViewに基づいて新しいクラスを作成し、そのユーザーインタラクションをYESに設定し、UIViewに2つのインスタンスを追加して、次のようにtouchesBeganメソッドを実装します。
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.tag == 1) {
self.backgroundColor= [UIColor redColor];
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];
});
[UIView animateWithDuration:0.25 animations:
^(){[self setFrame:CGRectInset(self.frame, 50, 50)];}];
}
}
タグ1をこれらのimageViewsのいずれかに割り当てます。
画像を読み込むビューから始めて、2つのビューをほぼ同時にタップすると正確に何が起こりますか? [self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];
が戻るのを待っているため、UIはブロックされますか?もしそうなら、どうすれば非同期でこれを行うことができますか?
githubのプロジェクト ipmccコード
長押ししてからドラッグして、黒い正方形の周りに長方形を描きます。彼の答えを理解しているように、理論的には、画像が最初にロードされるときに白い選択矩形がブロックされるべきではありませんが、実際にはブロックされます。
2つの画像がプロジェクトに含まれています(1つは小さい:woodenTile.jpgともう1つはbois.jpg)。結果は両方で同じです。
画像が初めて読み込まれているときにUIがブロックされるという問題とこれがどのように関係するのかはよくわかりませんが、PNG画像はUIをブロックせずにデコードしますが、JPG画像はUIをブロックします。
UIのブロックはここから始まります。
..そしてここで終わります。
NSURL * url = [ [NSBundle mainBundle]URLForResource:@"bois" withExtension:@"jpg"];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
[self.imageView setImageWithURLRequest:request
placeholderImage:[UIImage imageNamed:@"placeholder.png"]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
NSLog(@"success: %@", NSStringFromCGSize([image size]));
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"failure: %@", response);
}];
// this code works. Used to test that url is valid. But it's blocking the UI as expected.
if (false)
if (url) {
[self.imageView setImage: [UIImage imageWithData:[NSData dataWithContentsOfURL:url]]]; }
ほとんどの場合、ログに記録されます:success: {512, 512}
また、時々ログに記録します:success: {0, 0}
そして時々:failure: <NSURLResponse: 0x146c0000> { URL: file:///var/mobile/Appl...
ただし、イメージは変更されません。
問題は、UIImage
が実際に使用/描画されるまで画像を実際に読み取ったりデコードしたりしないことです。この作業をバックグラウンドスレッドで強制するには、メインスレッドを実行する前にバックグラウンドスレッドで画像を使用/描画する必要があります-setImage:
。これは私のために働いた:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage * img = [UIImage imageNamed:@"background.jpg"];
// Make a trivial (1x1) graphics context, and draw the image into it
UIGraphicsBeginImageContext(CGSizeMake(1,1));
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), [img CGImage]);
UIGraphicsEndImageContext();
// Now the image will have been loaded and decoded and is ready to rock for the main thread
dispatch_sync(dispatch_get_main_queue(), ^{
[[self imageView] setImage: img];
});
});
編集:UIはブロックしていません。特に、UILongPressGestureRecognizer
を使用するように設定しました。これは、デフォルトでは、何もする前に0.5秒待機します。メインスレッドはまだイベントを処理していますが、そのGRがタイムアウトするまで何も起こりません。これを行う場合:
longpress.minimumPressDuration = 0.01;
...あなたはそれがより速くなることに気付くでしょう。画像の読み込みはここでは問題ではありません。
編集2:私はiPad 2で実行されているgithubに投稿されたコードを見ましたが、あなたが説明しているしゃっくりを取得できません。実際、非常にスムーズです。以下は、CoreAnimationインストゥルメントでコードを実行したときのスクリーンショットです。
上のグラフを見るとわかるように、FPSは最大60FPSに達し、ジェスチャーの間中ずっとそこに留まります。一番下のグラフでは、画像が最初に読み込まれる約16秒でブリップが表示されますが、フレームレートの低下がないことがわかります。目視で確認すると、選択レイヤーが交差していることがわかります。最初の交差点と画像の外観の間には、わずかではありますが目に見える遅延があります。私が知る限り、バックグラウンドでロードするコードは期待どおりに機能しています。
もっとお役に立てればと思いますが、問題が発生していません。
AFNetworking libraryを使用できます。このライブラリでは、カテゴリをインポートすることにより
「UIImageView + AFNetworking.m」および次のメソッドを使用します。
[YourImageView setImageWithURL:[NSURL URLWithString:@"http://image_to_download_from_serrver.jpg"]
placeholderImage:[UIImage imageNamed:@"static_local_image.png"]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
//ON success perform
}
failure:NULL];
お役に立てれば 。
多くの画像をダウンロードする必要があり、UIが絶えず更新されていたアプリケーションで、同様の問題が発生しました。以下は、私の問題を解決した簡単なチュートリアルリンクです。
これは良い方法です:
-(void)updateImageViewContent {
dispatch_async(dispatch_get_main_queue(), ^{
UIImage * img = [UIImage imageNamed:@"background.jpg"];
[[self imageView] setImage:img];
});
}
AsyncImageView のようなサードパーティのライブラリを使用しないのはなぜですか?これを使用して、AsyncImageViewオブジェクトを宣言し、ロードするURLまたは画像を渡すだけです。画像の読み込み中にアクティビティインジケータが表示され、UIをブロックするものはありません。
-(void)touchesBegan:はメインスレッドで呼び出されます。 dispatch_async(dispatch_get_main_queue)を呼び出すことで、ブロックをキューに入れるだけです。このブロックは、キューの準備が整うとGCDによって処理されます(つまり、システムはタッチの処理を終了します)。そのため、指を離し、GCDがメインキューにキューイングされているすべてのブロックを処理するまで、woodenTileがロードされ、self.imageに割り当てられているのを確認できません。
交換:
dispatch_async(dispatch_get_main_queue(), ^{
[self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];
});
沿って :
[self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];
少なくとも問題を示すコードについては、問題を解決する必要があります。
アプリケーションでAFNetworkを使用している場合、AFNetworkがソリューションを提供するため、イメージのロードにブロックを使用する必要はありません。以下のように:
#import "UIImageView+AFNetworking.h"
そして
Use **setImageWithURL** function of AFNetwork....
ありがとう
SDWebImage の使用を検討してください。バックグラウンドでイメージをダウンロードおよびキャッシュするだけでなく、ロードおよびレンダリングも行います。
ダウンロードした後でも読み込みに時間がかかる大きな画像が含まれるテーブルビューで、良い結果で使用しました。
https://github.com/nicklockwood/FXImageView
これは、背景の読み込みを処理できる画像ビューです。
使用法
FXImageView *imageView = [[FXImageView alloc] initWithFrame:CGRectMake(0, 0, 100.0f, 150.0f)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.asynchronous = YES;
//show placeholder
imageView.processedImage = [UIImage imageNamed:@"placeholder.png"];
//set image with URL. FXImageView will then download and process the image
[imageView setImageWithContentsOfURL:url];
ファイルのURLを取得するには、次のことがおもしろいかもしれません。
私がそれを実装した1つの方法は次のとおりです:(それが最良のものかどうかはわかりませんが)
最初に、シリアル非同期または並列キューを使用してキューを作成します
queue = dispatch_queue_create("com.myapp.imageProcessingQueue", DISPATCH_QUEUE_SERIAL);**
or
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
**
あなたのニーズに合った方を見つけてください。
その後:
dispatch_async( queue, ^{
// Load UImage from URL
// by using ImageWithContentsOfUrl or
UIImage *imagename = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
// Then to set the image it must be done on the main thread
dispatch_sync( dispatch_get_main_queue(), ^{
[page_cover setImage: imagename];
imagename = nil;
});
});