CGPathRef 与 CGmutablePathRef

Posted

技术标签:

【中文标题】CGPathRef 与 CGmutablePathRef【英文标题】:CGPathRef vs. CGMutablePathRef 【发布时间】:2012-02-17 00:55:31 【问题描述】:

ios 中有两个 C 结构表示描述可绘制形状的路径:CGPathRef 和 CGMutablePathRef。从他们的名字看来,CGPathRef 指的是一个一旦创建就不能更改的路径,而 CGMutablePathRef 指的是一个可修改的路径。但是,事实证明,可以将 CGPathRef 传递给需要 CGMutablePathRef 的函数,在我看来,唯一的区别是前者会在传递给它的函数修改路径时生成警告,而后者不会吨。例如下面的程序:

#import <UIKit/UIKit.h>

@interface TestView : UIView 
    CGPathRef immutablePath;
    CGMutablePathRef mutablePath;

@end
@implementation TestView

- (id)initWithFrame:(CGRect)frame

    self = [super initWithFrame:frame];
    if (self) 
        mutablePath = CGPathCreateMutable();
        immutablePath = CGPathCreateCopy(mutablePath); // actually you might just do "immutablePath = CGPathCreateMutable();" here - The compiler doesn't even complain

        self.backgroundColor = [UIColor whiteColor];
    

    return self;



- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

    NSLog(@"touchesBegan executed!");
    [self setNeedsDisplay];


- (void)drawRect:(CGRect)rect

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextAddPath(context, immutablePath);
    CGPathAddRect(immutablePath, NULL, CGRectMake(100.0, 100.0, 200.0, 200.0)); // generates a warning specified later
    CGContextFillPath(context);



@end


@interface TestViewController : UIViewController
@end

@implementation TestViewController

@end

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

@implementation AppDelegate

@synthesize window = _window;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];

    // Instantiate view controller:
    TestViewController *vc = [[TestViewController alloc] init];
    vc.view = [[TestView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = vc;
    [self.window makeKeyAndVisible];
    return YES;

@end


int main(int argc, char *argv[])

    @autoreleasepool 
        return UIApplicationMain(argc, argv, nil, @"AppDelegate");
    

这是编译器给出的警告: 将“CGPathRef”(又名“const struct CGPath *”)传递给“CGMutablePathRef”(又名“struct CGPath *”)类型的参数会丢弃限定符

也许我在这里漏掉了重点,但这两者之间还有什么其他区别,除了提醒程序员他可能不打算修改被引用的路径(由 CGPathRef)吗?

【问题讨论】:

【参考方案1】:

在 C 中可能会向函数传递错误的类型,但这几乎总是不是一个好主意。即使从技术上讲,它们似乎被定义为同一个东西,但苹果将它们作为独立的东西可能是有充分理由的。很可能是为了让代码更具可读性和可理解性,或者 Apple 计划稍后进行更改。

毕竟,跳转到定义会揭示真正的差异:

typedef struct CGPath *CGMutablePathRef;
typedef const struct CGPath *CGPathRef;

CGPathRefconst typedef(如果您不太确定这是做什么的,请在 Google 上搜索)。但是,C 允许您打破 const 定义,这就是为什么您仍然能够将 CGPathRef 传递给期望 CGMutablePathRef 的函数并对其进行很好的修改的原因。它还解释了为什么它会引发 discards qualifiers 警告。

【讨论】:

我知道在 C 中可以将 const 指针转换为非 const 指针但是,这种转换似乎发生在 Apple 自己的库函数中的事实对我来说似乎有点时髦 -尽管有警告(错误似乎更合适)。但我想根据他们的定义,不可能有更多的东西了。 恕我直言,这样的转换对于 Objective-C 对象模型的动态类型是必不可少的。 重点是,您必须保持 const 正确性。即使它看起来有效,修改 const 限定的对象也会导致未定义的行为。这不是“苹果自己的库不一致”,苹果与此无关。如果方法期望它是可变的,则必须传入一个可变对象。 你的权利打破 const 是个坏主意,我不提倡这样做,通过你应该做的事

以上是关于CGPathRef 与 CGmutablePathRef的主要内容,如果未能解决你的问题,请参考以下文章

CGMutablePath 总是从 0,0 开始

iOS:获取 CGMutablePath 不在 drawRect 中:并将其分配给 CAShapeLayer 的路径

用 CGPathRef 屏蔽 CGContext?

iOS 绘图-UIBezierPath

从黑白位图图像中提取路径信息

如何缩放图形,使用 CGContextRef 创建