60

連絡先アプリの連絡先画像のように、角を丸くしてiPhoneで画像を描画しようとしています。通常は動作するコードがありますが、UIImage 描画ルーチン内でEXEC_BAD_ACCESS-でクラッシュすることがありますKERN_INVALID_ADDRESSこれは、数週間前に行ったクロッピングの質問に関連している可能性があると思いましたが、クリッピング パスを正しく設定していると思います。

私が使用しているコードは次のとおりです。クラッシュしない場合、結果は問題ないように見えます。同様の外観を探している人は、コードを自由に借りることができます。

- (UIImage *)borderedImageWithRect: (CGRect)dstRect radius:(CGFloat)radius {
    UIImage *maskedImage = nil;

    radius = MIN(radius, .5 * MIN(CGRectGetWidth(dstRect), CGRectGetHeight(dstRect)));
    CGRect interiorRect = CGRectInset(dstRect, radius, radius);

    UIGraphicsBeginImageContext(dstRect.size);
    CGContextRef maskedContextRef = UIGraphicsGetCurrentContext();
    CGContextSaveGState(maskedContextRef);

    CGMutablePathRef borderPath = CGPathCreateMutable();
    CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMinY(interiorRect), radius, PNDegreeToRadian(180), PNDegreeToRadian(270), NO);
    CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMinY(interiorRect), radius, PNDegreeToRadian(270.0), PNDegreeToRadian(360.0), NO);
    CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMaxY(interiorRect), radius, PNDegreeToRadian(0.0), PNDegreeToRadian(90.0), NO);
    CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMaxY(interiorRect), radius, PNDegreeToRadian(90.0), PNDegreeToRadian(180.0), NO);

    CGContextBeginPath(maskedContextRef);
    CGContextAddPath(maskedContextRef, borderPath);
    CGContextClosePath(maskedContextRef);
    CGContextClip(maskedContextRef);

    [self drawInRect: dstRect];

    maskedImage = UIGraphicsGetImageFromCurrentImageContext();
    CGContextRestoreGState(maskedContextRef);
    UIGraphicsEndImageContext();

    return maskedImage;
}

これがクラッシュログです。これらのクラッシュのいずれかが発生するたびに、同じように見えます

例外の種類: EXC_BAD_ACCESS (SIGSEGV)
例外コード: 0x6e2e6181 の KERN_INVALID_ADDRESS
クラッシュしたスレッド: 0

スレッド 0 がクラッシュしました:
0 com.apple.CoreGraphics 0x30fe56d8 CGGStateGetRenderingIntent + 4
1 libRIP.A.dylib 0x33c4a7d8 ripc_RenderImage + 104
2 libRIP.A.dylib 0x33c51868 ripc_DrawImage + 3860
3 com.apple.CoreGraphics 0x30fecad4 CGContextDelegateDrawImage + 80
4 com.apple.CoreGraphics 0x30feca40 CGContextDrawImage + 368
5 UIKit 0x30a6a708 -[UIImage drawInRect:blendMode:alpha:] + 1460
6 UIKit 0x30a66904 -[UIImage drawInRect:] + 72
7 MyApp 0x0003f8a8 -[UIImage(PNAdditions) borderedImageWithRect:radius:] (UIImage+PNAdditions.m:187)
4

12 に答える 12

165

これは、iPhone 3.0 以降で利用できるさらに簡単な方法です。すべてのビューベースのオブジェクトには、関連付けられたレイヤーがあります。各レイヤーにはコーナー半径を設定できます。これにより、必要なものが得られます。

UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]];
// Get the Layer of any view
CALayer * l = [roundedView layer];
[l setMasksToBounds:YES];
[l setCornerRadius:10.0];

// You can even add a border
[l setBorderWidth:4.0];
[l setBorderColor:[[UIColor blueColor] CGColor]];
于 2009-08-20T17:33:08.700 に答える
27

ここで先に進み、実際にタイトルの質問に答えます。

このカテゴリを試してみてください。

UIImage+additions.h

#import <UIKit/UIKit.h>

@interface UIImage (additions)
-(UIImage*)makeRoundCornersWithRadius:(const CGFloat)RADIUS;
@end

UIImage+additions.m

#import "UIImage+additions.h"

@implementation UIImage (additions)
-(UIImage*)makeRoundCornersWithRadius:(const CGFloat)RADIUS {
    UIImage *image = self;

    // Begin a new image that will be the new image with the rounded corners
    // (here with the size of an UIImageView)
    UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);

    const CGRect RECT = CGRectMake(0, 0, image.size.width, image.size.height);
    // Add a clip before drawing anything, in the shape of an rounded rect
    [[UIBezierPath bezierPathWithRoundedRect:RECT cornerRadius:RADIUS] addClip];
    // Draw your image
    [image drawInRect:RECT];

    // Get the image, here setting the UIImageView image
    //imageView.image
    UIImage* imageNew = UIGraphicsGetImageFromCurrentImageContext();

    // Lets forget about that we were drawing
    UIGraphicsEndImageContext();

    return imageNew;
}
@end
于 2013-09-03T06:56:36.827 に答える
22

appIconImage が UIImageView の場合:

appIconImage.image = [UIImage imageWithContentsOfFile:@"image.png"]; 
appIconImage.layer.masksToBounds = YES;
appIconImage.layer.cornerRadius = 10.0;
appIconImage.layer.borderWidth = 1.0;
appIconImage.layer.borderColor = [[UIColor grayColor] CGColor];

また、次のことも覚えておいてください。

#import <QuartzCore/QuartzCore.h>
于 2009-09-22T20:14:52.707 に答える
4

バックグラウンドスレッドでメソッド(borderedImageWithRect)を呼び出している場合、UIGraphics関数はスレッドセーフではないため、クラッシュが発生する可能性があります。このような場合は、CGBitmapContextCreate()を使用してコンテキストを作成する必要があります。SDKの「Reflection」サンプルコードを参照してください。

于 2009-01-17T01:38:00.553 に答える
4

あなたのクラッシュについての洞察を提供することはできませんが、コーナーを丸めるための別のオプションを提供すると思いました. 私が取り組んでいたアプリケーションで同様の問題が発生しました。コードを書くのではなく、コーナーをマスクする別の画像をオーバーレイしています。

于 2008-10-15T17:28:41.907 に答える
3

最も簡単な方法は、disabled[!] round-rect [not custom!] ボタンをビューに埋め込み (Interface Builder ですべて行うこともできます)、画像をそれに関連付けることです。UIButton のイメージ設定メッセージは (UIImageView と比較して) 異なりますが、全体的なクラッジは魅力のように機能します。中央揃えのアイコンが必要な場合は setImage:forState: を使用し、(連絡先のように) 角を切り取った画像全体が必要な場合は setBackgroundImage:forState: を使用します。もちろん、 drawRect にこれらの画像をたくさん表示したい場合、これは正しいアプローチではありませんが、埋め込みビューはとにかく必要なものである可能性が高くなります...

于 2008-12-17T00:47:16.613 に答える
2

私は実際、ニューヨークで開催されたiPhone Tech Talkで、Appleの誰かとこれについて話す機会がありました。私たちがそれについて話したとき、彼はそれがスレッド化されたものではないとかなり確信していました。代わりに、彼は、を呼び出したときに生成されたグラフィックスコンテキストを保持する必要があると考えましたUIGraphicsBeginImageContext。これは、保持ルールと命名スキームを扱う一般的なルールに違反しているようですが、この仲間は、以前にこの問題を確認したことがあると確信していました。

おそらく別のスレッドによってメモリが走り書きされていた場合、それは確かに私がたまにしか問題を見ていない理由を説明します。

コードを再検討して修正をテストする時間がありませんでしたが、PCheeseのコメントにより、ここに情報を投稿していないことに気づきました。

...私がそれを間違って書き留めて、そうUIGraphicsBeginImageContextすべきだったのでなければCGBitmapContextCreate...

于 2009-02-04T10:10:58.350 に答える
2

fjoachimの答えを繰り返します。別のスレッドで実行しているときに描画しようとすると、EXC_BAD_ACCESSエラーが発生する可能性があるので注意してください。

私の回避策は次のようになりました。

UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"] 
[self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES];

(私の場合、UIImagesのサイズ変更/スケーリングを行っていました。)

于 2009-02-04T05:57:15.100 に答える
1

ときどきクラッシュする場合は、クラッシュ ケースの共通点を見つけてください。dstRect は毎回同じですか? 画像のサイズが異なることはありますか?

CGPathRelease(borderPath)また、リークが問題を引き起こしているとは思えませんが、する必要があります。

于 2008-10-15T19:07:13.157 に答える