Mac应用开发与图形编程指南
一、应用开发操作流程
-
绑定操作
- 选择Album表列,打开Bindings Inspector。将Value绑定到Photos,设置Controller Key为arrangedObjects,Model Key Path为album.title。
- 选择File Path表列,在Bindings Inspector中,将Value绑定到Photos,Controller Key为arrangedObjects,Model Key Path为filePath。
-
连接出口
- 右键点击File’s Owner图标,将imagesArrayController出口连接到Photos数组控制器。
- 将imagesTable出口连接到表格视图。
- 保存并关闭XIB文件,切换回Xcode。
-
运行应用程序
- 保存Xcode或Interface Builder中所有打开的文件,按Command - R构建并运行项目。
- 应用程序运行后,在Mac上找到一些照片,将它们拖到浏览器视图中。尝试重新排列照片。
- 可以从Album菜单创建新相册,并拖入不同的照片。
- 在浏览器或列表视图中双击图像,可在编辑器视图中打开它。在编辑器视图中双击图像,可调出图像调整面板。
- 退出应用程序时,Core Data会自动保存数据。添加一些照片和相册,然后按Command - Q退出。重新启动应用程序,所有数据将恢复。如果要永久删除保存的数据,删除/Users/ /Library/Application Support中的CocoaBookGallery文件夹。注意,点击Xcode工具栏中的Tasks停止图标,数据不会保存,这相当于强制退出。
-
准备发布
- 若要在Xcode之外或另一台Mac上运行应用程序,需使用Release配置进行构建。从Xcode工具栏中选择Release作为活动配置。
- 验证活动架构为x86_64。双击Xcode侧边栏顶部的Gallery项目图标,打开项目检查器,确保Architectures字段仅为64位Intel。
- 按Command - R构建并运行,确保一切正常。此构建可能比Debug构建耗时更长。
- 打开Xcode侧边栏底部附近的Products组,右键点击Gallery.app,选择Reveal in Finder,可在Finder中找到完成的Gallery应用程序(无需复制标记为Gallery.app.dSYM的文件),可将该文件复制到任何运行Snow Leopard的64位Mac上。
二、Mac OS X图形框架介绍
Mac OS X有多个图形框架可供选择,每个框架都有其特点:
| 框架名称 | 特点 |
| ---- | ---- |
| AppKit | Cocoa的UI部分,有处理颜色、几何、样式文本、位图图像和复杂路径的类和方法,是为Mac UI编写自定义绘图代码的首选。 |
| Core Graphics | 基于C的底层2D绘图框架,也是iPhone SDK的一部分,代码可轻松共享,但C函数和内存管理不如Objective - C的AppKit绘图类方便灵活。 |
| Core Animation | 相对较新的框架,基于OpenGL,可实现许多令人印象深刻的3D和过渡效果,有易于使用的Objective - C接口,使用GPU,速度极快,某些情况下可与AppKit结合使用。 |
| Core Image | 可对图像和视图应用特殊效果,如高斯模糊、光晕、颜色调整以及页面卷曲和溶解等过渡效果,通常与其他框架结合使用,目前在iPhone SDK中不可用。 |
三、基本几何知识
-
几何结构体定义
- NSPoint :表示视图中的一个点,有x和y坐标,是CGPoint的别名。
typedef CGPoint NSPoint;
struct CGPoint {
CGFloat x;
CGFloat y;
};
typedef struct CGPoint CGPoint;
- **NSSize**:有宽度和高度两个浮点值,与CGSize类型可互换。
typedef CGSize NSSize;
struct CGSize {
CGFloat width;
CGFloat height;
};
typedef struct CGSize CGSize;
- **NSRect**:由一个NSPoint类型的origin字段和一个NSSize类型的size字段组成,基于CGRect。
typedef CGRect NSRect;
struct CGRect {
CGPoint origin;
CGSize size;
};
typedef struct CGRect CGRect;
-
几何结构体的创建
- NSPoint创建示例
NSPoint point1;
point1.x = 4;
point1.y = 11;
NSPoint point2;
point2.x = 12;
point2.y = 21;
NSPoint point3 = NSMakePoint ( 19, 8 );
NSPoint point4 = NSMakePoint ( 24, 18 );
- **NSSize创建示例**
NSSize size1;
size1.width = 1920;
size1.height = 1200;
NSSize size2;
size2.width = 16;
size2.height = 16;
NSSize size3 = NSMakeSize ( 1024, 768 );
NSSize size4 = NSMakeSize ( 640, 480 );
- **NSRect创建示例**
// create a rect from separate point and size variables.
NSPoint origin1 = NSMakePoint ( 0, 0 );
NSSize size1 = NSMakeSize ( 40, 40 );
NSRect rect1;
rect1.origin = origin1;
rect1.size = size1;
// create a rect one field at a time.
NSRect rect2;
rect2.origin.x = 4;
rect2.origin.y = 4;
rect2.size.width = 32;
rect2.size.height = 32;
// create the whole rect in a single line.
rect3 = NSMakeRect ( 20, 80, 200, 200 );
-
几何结构体与字符串、NSValue的转换
- 转换为字符串 :使用NSStringFromRect()、NSStringFromSize()和NSStringFromPoint()函数将几何结构体转换为字符串。
NSRect rect1 = NSMakeRect ( 0, 0 , 200, 400 );
NSString* rectString1 = NSStringFromRect ( rect1 );
NSLog ( @"rect1: %@", rectString1 );
NSSize size1 = NSMakeSize ( 256, 256 );
NSString* sizeString1 = NSStringFromSize ( size1 );
NSLog ( @"size1: %@", sizeString1 );
NSPoint point1 = NSMakePoint ( 100, 100 );
NSString* pointString1 = NSStringFromPoint ( point1 );
NSLog ( @"point1: %@", pointString1 );
- **从字符串转换回结构体**:使用NSRectFromString()、NSSizeFromString()和NSPointFromString()函数。
NSString* rectPlist = @"{{0, 0}, {200, 400}}";
NSString* sizePlist = @"{256, 256}";
NSString* pointPlist = @"{100, 100}";
NSRect rect1 = NSRectFromString ( rectPlist );
NSSize size1 = NSSizeFromString ( sizePlist );
NSPoint point1 = NSPointFromString ( pointPlist );
- **转换为NSValue**:使用NSValue的+valueWithRect:、+valueWithSize:和+valueWithPoint:方法将几何结构体转换为NSValue对象,存储在集合中。
NSRect newRect = NSMakeRect ( 10, 10, 100, 100 );
NSSize newSize = NSMakeSize ( 40, 40 );
NSPoint newPoint = NSMakePoint ( 4, 4 );
NSValue* rectObject = [NSValue valueWithRect:newRect];
NSValue* sizeObject = [NSValue valueWithSize:newSize];
NSValue* pointObject = [NSValue valueWithPoint:newPoint];
NSMutableArray* array = [NSMutableArray array];
[array addObject:rectObject];
[array addObject:sizeObject];
[array addObject:pointObject];
NSLog ( @"NSValue 0: %@", [array objectAtIndex:0] );
NSLog ( @"NSValue 1: %@", [array objectAtIndex:1] );
NSLog ( @"NSValue 2: %@", [array objectAtIndex:2] );
- **从NSValue转换回结构体**:使用-rectValue、-sizeValue或-pointValue方法。
NSRect newRect = NSMakeRect ( 0, 0, 80, 180 );
NSSize newSize = NSMakeSize ( 16, 16 );
NSPoint newPoint = NSMakePoint ( 0, 0 );
NSValue* rectObject = [NSValue valueWithRect:newRect];
NSValue* sizeObject = [NSValue valueWithSize:newSize];
NSValue* pointObject = [NSValue valueWithPoint:newPoint];
// convert the contents of the NSValue object back
// into a geometry struct.
NSRect storedRect = rectObject.rectValue;
NSSize storedSize = sizeObject.sizeValue;
NSPoint storedPoint = pointObject.pointValue;
四、Cocoa视图坐标
- 视图层次结构 :Cocoa应用程序中的大多数屏幕控件是NSView的子类。视图是视图层次结构的一部分,窗口有一个内容视图,它是该窗口的根视图,内容视图可以有任意数量的子视图,每个子视图又可以有自己的子视图,每个窗口本质上有一个以内容视图为根的视图“树”。
- 视图的坐标属性 :视图有两个NSRect属性来描述其大小和位置,bounds是视图的内部坐标系,frame是视图在其父视图内的坐标。要在窗口内移动视图,需更改其frame。
- 坐标系统 :Cocoa默认使用笛卡尔坐标系,原点在左下角,值越大越向上和向右,这与iPhone和HTML/CSS坐标系统不同,后者原点在左上角。可通过在NSView子类中实现-isFlipped方法并返回YES来更改此行为,但不强烈推荐,建议使用标准系统,尤其是使用Core Animation时。
五、派生矩形与比较函数
-
派生矩形函数
- NSOffsetRect() :获取一个矩形的副本并按指定量移动。
NSRect rect1;
rect1.origin.x = 100;
rect1.origin.y = 100;
rect1.size.width = 30;
rect1.size.height = 25;
NSRect rect2 = NSOffsetRect ( rect1, 5, 10 );
NSRect rect3 = NSOffsetRect ( rect1, -40, -60 );
- **NSIntersectionRect()**:获取两个矩形的重叠区域。
NSRect rect1 = NSMakeRect ( 0, 0, 30, 25 );
NSRect rect2 = NSMakeRect ( 5, 5, 30, 25 );
NSRect rect3 = NSIntersectionRect ( rect1, rect2 );
- **NSUnionRect()**:获取一个完全包围两个输入矩形的矩形。
NSRect rect1;
rect1.origin.x = 0;
rect1.origin.y = 0;
rect1.size.width = 30;
rect1.size.height = 25;
NSRect rect2 = rect1;
rect2.origin.x += 5;
rect2.origin.y += 10;
NSRect rect3 = NSUnionRect ( rect1, rect2 );
- **NSInsetRect()**:获取一个矩形的“内缩”或“外扩”版本。
NSRect rect1;
rect1.origin.x = 0;
rect1.origin.y = 0;
rect1.size.width = 30;
rect1.size.height = 25;
NSRect rect2 = NSInsetRect ( rect1, 2, 2 );
NSRect rect3 = NSInsetRect ( rect1, -10, -20 );
-
比较函数
- 使用NSEqualPoints()、NSEqualRects()和NSEqualSizes()比较几何结构体。
NSRect rect1 = NSMakeRect ( 0, 0, 280, 101);
NSRect rect2;
rect2.origin.x = 0;
rect2.origin.y = 0;
rect2.size.width = 280;
rect2.size.height = 101;
if ( NSEqualRects ( rect1, rect2 ) )
NSLog (@"rect1 and rect2 are equal");
NSSize size1 = NSMakeSize ( 42, 42 );
NSSize size2 = NSMakeSize ( 24, 24 );
if ( NSEqualSizes ( size1, size2) )
NSLog (@"size1 and size2 are equal");
NSPoint point1 = NSMakePoint ( 0, 0 );
if ( NSEqualPoints ( point1, NSZeroPoint ) )
NSLog (@"point1 and NSZeroPoint are equal");
- 空间比较函数
| 方法 | 描述 |
|---|---|
| NSIntersectsRect() | 如果矩形至少部分重叠,返回YES |
| NSContainsRect() | 如果第一个矩形完全包含第二个矩形,返回YES |
| NSPointInRect() | 如果点在矩形内,返回YES |
NSRect rect1 = NSMakeRect ( 10, 10, 40, 40 );
NSRect rect2 = NSMakeRect ( 10, 10, 500, 500 );
if ( NSIntersectsRect ( rect1, rect2 ))
NSLog (@"rect1 intersects rect2");
if ( NSContainsRect ( rect1, rect2 ))
NSLog (@"rect1 contains rect2");
NSPoint point1 = NSMakePoint ( 10, 10 );
NSRect rect3 = NSMakeRect ( 0, 0, 200, 200 );
NSView* view = [[NSView alloc] initWithFrame:rect3];
if ( NSPointInRect ( point1, view.frame ))
NSLog (@"point1 is inside the view");
[view release];
六、基本绘图
要进行绘图,有三个必要条件:颜色、要绘制的对象和绘图的位置。使用NSColor类创建颜色,可从简单的矩形开始绘制,绘图位置通常是一个视图。
Mac应用开发与图形编程指南
七、基本绘图的实践步骤
在了解了基本绘图的必要条件后,下面详细说明如何进行基本绘图的操作。
1.
创建颜色
:利用
NSColor
类来创建颜色。例如,创建红色:
NSColor *redColor = [NSColor redColor];
-
选择绘图对象
:以简单的矩形为例,我们可以使用之前提到的
NSRect结构体来定义矩形的大小和位置。
NSRect rect = NSMakeRect(50, 50, 200, 150);
-
设置绘图上下文
:在进行绘图之前,需要设置绘图上下文。这里我们假设在一个自定义的
NSView子类中进行绘图,重写drawRect:方法。
- (void)drawRect:(NSRect)dirtyRect {
// 获取当前的绘图上下文
NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
// 设置填充颜色
NSColor *fillColor = [NSColor blueColor];
[fillColor setFill];
// 绘制矩形
NSRectFill(rect);
}
在上述代码中,首先获取当前的绘图上下文,然后设置填充颜色为蓝色,最后使用
NSRectFill
函数绘制矩形。
八、图形编程框架的选择建议
在进行图形编程时,如何选择合适的框架是一个关键问题。下面为不同场景提供一些框架选择建议:
| 场景 | 推荐框架 | 原因 |
| ---- | ---- | ---- |
| 快速开发Mac UI自定义绘图 | AppKit | 具有丰富的类和方法,可处理颜色、几何、样式文本等,且使用Objective - C,开发便捷 |
| 需要跨Mac和iPhone平台共享代码 | Core Graphics | 是iPhone SDK的一部分,代码可共享,但C函数和内存管理需注意 |
| 实现3D和过渡效果 | Core Animation | 基于OpenGL,有简单的Objective - C接口,使用GPU速度快 |
| 应用图像特殊效果 | Core Image | 可实现高斯模糊、颜色调整等效果,通常与其他框架结合使用 |
九、图形编程的常见误区与解决方法
在图形编程过程中,可能会遇到一些常见的误区,以下是一些常见问题及解决方法:
1.
坐标系统混淆
:由于Cocoa默认使用笛卡尔坐标系,而iPhone和HTML/CSS使用左上角为原点的坐标系,容易造成混淆。解决方法是在开发过程中明确使用的坐标系统,尽量遵循标准系统,尤其是使用Core Animation时。
2.
内存管理问题
:在使用Core Graphics时,C函数的内存管理不如Objective - C方便,容易出现内存泄漏。解决方法是仔细阅读文档,正确使用内存分配和释放函数,例如
CGContextRelease
等。
3.
代码兼容性问题
:不同版本的Mac OS X和iPhone OS对图形框架的支持可能有所不同。解决方法是在开发前了解目标平台的版本要求,进行充分的测试。
十、图形编程的优化策略
为了提高图形编程的性能和效果,可以采用以下优化策略:
1.
减少重绘区域
:在
drawRect:
方法中,只重绘需要更新的区域,避免不必要的重绘。可以使用
NSIntersectionRect
函数来计算需要重绘的区域。
NSRect dirtyRect = [self bounds];
NSRect redrawRect = NSIntersectionRect(dirtyRect, rect);
if (!NSIsEmptyRect(redrawRect)) {
// 进行重绘操作
}
- 使用缓存 :对于一些复杂的图形绘制,可以将绘制结果缓存起来,下次需要时直接使用缓存结果,减少重复计算。
- 合理使用GPU :Core Animation和Core Graphics都可以利用GPU来提高性能。在开发过程中,尽量使用这些支持GPU加速的框架。
十一、总结与展望
通过以上内容,我们详细介绍了Mac应用开发中的图形编程相关知识,包括开发操作流程、图形框架介绍、基本几何知识、视图坐标、派生矩形与比较函数、基本绘图等方面。在实际开发中,需要根据具体需求选择合适的框架和方法,同时注意避免常见误区,采用优化策略提高性能。
未来,随着技术的不断发展,图形编程领域将会有更多的创新和突破。例如,更强大的GPU支持将使得3D和动画效果更加逼真和流畅;新的图形算法和技术将为开发者提供更多的创意空间。我们期待在未来的开发中,能够利用这些新技术创造出更加出色的图形应用。
下面是一个简单的mermaid流程图,展示基本绘图的流程:
graph TD;
A[创建颜色] --> B[选择绘图对象];
B --> C[设置绘图上下文];
C --> D[进行绘图操作];
希望以上内容对大家在Mac应用开发和图形编程方面有所帮助,大家可以根据这些知识进行实践和探索,不断提升自己的开发能力。
超级会员免费看

被折叠的 条评论
为什么被折叠?



