Ios CGPathRef与CGMutablePathRef

Ios CGPathRef与CGMutablePathRef,ios,cocoa-touch,core-graphics,Ios,Cocoa Touch,Core Graphics,在iOS中,有两个C结构表示描述可绘制形状的路径:CGPathRef和CGMutablePathRef。从它们的名称来看,似乎CGPathRef指的是一个一旦创建就无法更改的路径,而CGMutablePathRef指的是一个可修改的路径。然而,事实证明,CGPathRef可以传递给需要CGMutablePathRef的函数,在我看来,唯一的区别是,如果传递给它的函数修改了路径,前者会生成警告,而后者则不会。例如,以下程序: #import <UIKit/UIKit.h> @inte

在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");
    }
}
#导入
@接口测试视图:UIView{
CGPathRef不可变路径;
CGMutablePathRef mutablePath;
}
@结束
@实现测试视图
-(id)initWithFrame:(CGRect)帧
{
self=[super initWithFrame:frame];
如果(自我){
mutablePath=CGPathCreateMutable();
immutablePath=CGPathCreateCopy(mutablePath);//实际上您可以在这里执行“immutablePath=CGPathCreateMutable();”——编译器甚至不会抱怨
self.backgroundColor=[UIColor whiteColor];
}
回归自我;
}
-(无效)触摸开始:(NSSet*)触摸事件:(UIEvent*)事件
{
NSLog(@“TouchesBegind executed!”);
[自我设置需要显示];
}
-(void)drawRect:(CGRect)rect
{
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextAddPath(上下文,不可变路径);
CGPathAddRect(immutablePath,NULL,CGRectMake(100.0,100.0,200.0,200.0));//生成稍后指定的警告
CGContextFillPath(上下文);
}
@结束
@接口TestViewController:UIViewController
@结束
@TestViewController的实现
@结束
@接口AppDelegate:UIResponder
@属性(强,非原子)UIWindow*window;
@结束
@实现AppDelegate
@合成窗口=_窗口;
-(BOOL)应用程序:(UIApplication*)应用程序使用选项完成启动:(NSDictionary*)启动选项
{
self.window=[[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
//应用程序启动后自定义的覆盖点。
self.window.backgroundColor=[UIColor whiteColor];
//实例化视图控制器:
TestViewController*vc=[[TestViewController alloc]init];
vc.view=[[TestView alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController=vc;
[self.window makeKeyAndVisible];
返回YES;
}
@结束
int main(int argc,char*argv[])
{
@自动释放池{
返回UIApplicationMain(argc、argv、nil、@“AppDelegate”);
}
}
这是编译器发出的警告: 将“CGPathRef”(又名“const struct CGPath*)传递给类型为“CGMutablePathRef”(又名“struct CGPath*)的参数将丢弃限定符


也许我没有抓住要点,但是这两者之间还有什么区别吗?除了提醒程序员他可能不想修改(由CGPathRef)引用的路径?

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

在所有这些之后,跳转到定义揭示了真正的区别:

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

CGPathRef
是一个
consttypedef
(如果您不太确定它的作用,请用谷歌搜索它)。然而,C允许您中断常量定义,这就是为什么您仍然能够将
CGPathRef
传递给一个需要
CGMutablePathRef
的函数并对其进行良好修改的原因。它还解释了为什么它抛出一个
丢弃限定符
警告。

我知道在C中,常量指针可以被强制转换为非常量指针。然而,这个强制转换似乎发生在苹果自己的库函数中,这一事实对我来说似乎有点奇怪——尽管有警告(一个错误似乎更合适)。但是根据他们的定义,我想没有更多的了。IMHO,这种类型转换对于Objective-C对象模型的动态类型化是必不可少的。关键是,你必须保持常量的正确性。即使它看起来有效,修改const限定对象也会导致未定义的行为。这不是“苹果自己的图书馆中的不一致”,苹果与此无关。如果一个方法希望一个可变对象是可变的,那么你必须传入它。你的权利打破常量是个坏主意,我不主张这样做,传递你应该传递的东西