In iOS there are two C structs that denote paths that describe drawable shapes: CGPathRef and CGMutablePathRef. From their names it would seem that CGPathRef refers to a path that once created cannot be changed, while CGMutablePathRef refers to a modifiable path. However, as it turns out, a CGPathRef can be passed to a function that expects a CGMutablePathRef and it appears to me the only difference is that the former generates a warning if the function it is passed to modifies the path, while the latter doesn’t. For example, the following program:
#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");
}
}
This is the warning given by the compiler:
Passing ‘CGPathRef’ (aka ‘const struct CGPath *’) to parameter of type ‘CGMutablePathRef’ (aka ‘struct CGPath *’) discards qualifiers
Maybe I’m missing the point here, but is there any other difference between these two except to remind the programmer that maybe he didn’t intend the path being referenced (by CGPathRef) to be modified?
It is possible in C to pass the wrong type to a function, but it is almost always not a good idea. Even if technically they might appear to be defined the same thing, there is probably a good reason Apple has them as separate things. Most likely it is to make more code readable and understandable, or Apple plans on making changes later.
After all that, a jump to definition reveals the real differences:
CGPathRefis aconst typedef(google it if you’re not quite sure what this does). However C allows you to break const definitions which is why you are still able to pass yourCGPathRefto a function expecting aCGMutablePathRefand modify it fine. It also explains why it throws adiscards qualifierswarning.