CGPathRef против CGMutablePathRef

В 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)?


person Aky    schedule 17.02.2012    source источник


Ответы (1)


В C можно передать функции неправильный тип, но это почти всегда не очень хорошая идея. Даже если технически они могут показаться одним и тем же, вероятно, есть веская причина, по которой Apple считает их отдельными вещами. Скорее всего, это делается для того, чтобы сделать код более читаемым и понятным, или Apple планирует внести изменения позже.

После всего этого переход к определению показывает реальные различия:

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

CGPathRef - это const typedef (погуглите, если вы не совсем уверены, что он делает). Однако C позволяет вам нарушать определения констант, поэтому вы все еще можете передать свой CGPathRef функции, ожидающей CGMutablePathRef, и изменить ее нормально. Это также объясняет, почему он выдает discards qualifiers предупреждение.

person Justin Meiners    schedule 17.02.2012
comment
Я знаю, что в C константный указатель может быть преобразован в неконстантный. показалось более подходящим). Но я полагаю, что в свете их определений и быть не может. - person Aky; 17.02.2012
comment
IMHO, такие приведения необходимы для динамической типизации объектной модели Objective-C. - person ZhangChn; 17.02.2012
comment
Дело в том, что вы должны поддерживать правильность констант. Даже если кажется, что это работает, изменение объекта с атрибутом const приводит к неопределенному поведению. Это не противоречие в собственной библиотеке Apple, Apple тут ни при чем. Вы должны передать изменяемый объект, если метод ожидает, что он будет изменяемым. - person ; 21.05.2013
comment
ваше право - плохая идея ломать const, я не защищаю этого, передайте то, что вы должны - person Justin Meiners; 22.05.2013