Cocoa
Cocoa基于Quartz,采用Painter model来绘制
Painter model主要是在一个连续的绘制操作中会将一层的绘制应用于一个output 画布(canvas)上
在添加新的绘制层(layers of paints)时先前的绘制层可能被覆盖或者修改
绘制环境(drawing enviroment)
包含数字画布(digital canvas)和图形设置(graphics setting) 数字画布决定了你在哪绘制,而图形设置控制绘画的每一方面,包括大小,颜色,方向等等
绘制上下文(draw context)
封装了绘制在画布上的所有信息 包含当前绘制的属性和 device-specific representation of the digital paint on the canvas 还不能理解什么意思
坐标系
用户坐标空间:使用固定比例的坐标值 一个单位实际上等于1/72英寸,但是实际上坐标控件并没有像素和英寸(dpi)的概念
设备坐标空间:主要依赖于使用设备的本地坐标空间,主要于设备分辨率有关
视图绘制
当view需要绘制的时候 cocoa会给这个视图发一个drawRect消息,然后就会调用drawRect方法
XIB/storyboard
本质都是将可视化的窗口转换成代码去创建控件
区别
Xib是轻量级的,用来描述局部的UI界面 XIB一般用来封装独立控件
XIB实现了控件的添加与frame的设置这两步?(没看懂)
xib是IB编译过程中的一种文件类型 nib是该工程编译后
Storyboard是重量级的,用来描述整个软件的多个界面,并且能展示多个界面之间的跳转关系
Storyboard可以简单理解成一组与viewController关联的xib的集合 该集合中也同时保存了各个viewChontroller之间跳转的数据
XiB初始化
懒加载
用到的时候再加载 并且只加载一次
比如说在调用的时候会判断一下这个对象是否为空 如果为空才会进行一次创建 这样就避免了重复创建
loadNibNamed
会通过NibName寻找和NibName相同的xib文件进行load
//一
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
if (![bundle loadNibNamed:self.className owner:self topLevelObjects:nil]) {
return;
}
//二
HYLShopView *shopView=[[[NSBundle mainBundle]loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil] firstObject];
initWithNibName/initWithWindowNibName(获取windowController的办法)
这个的主要作用是返回Xib的控制权
@interface CustomWindowController ()
@end
@implementation CustomWindowController
-(id)initGetWindowController{
//self = [super initWithNibName:NSStringFromClass([self class]) bundle:[NSBundle bundleForClass:[self class]]];
self = [super initWithWindowNibName:NSStringFromClass([self class])];//这里获取xib的windowController
return self;
}
@end
此时就可以在其他的类或者window里面去获取这个window的controller
CustomWindowController* windowController = [CustomWindowController alloc]initGetWindowController]
XIB中File’s Owner应该是程序的NSApplication对象 NSApplication对象从时间队列中取得事件 转发给相应的窗口
指向别的对象的成员变量指针叫做outlet
IBAction等价于void
awakeFromNib
当awakeFromNib方法被调用时,所有视图的outlet和action已经连接,但还没有被确定
NIB文件是应用程序所有对象的存档
当程序启动后 对象从文件中释放 重新赋予声明 准备接收用户出发的事件信息
在获得声明后 并没有接收到用户的事件信息以前 所有的对象自动发送awakeFormNib消息
awakeFromNib
运行过程
awakeFromNib->applicationDidFinishLaunching
这个awakeFormNib的Nib是项目创建的时候自带的那个xib文件
首先运行NSApplicationMain函数
创建一个NSApplication的实例
应用程序对象读取main NIB文件内容 将归档的对象释放出来
NIB文件中的每个对象都发送awakeFromNib消息
应用程序对象开始检查是否有时间发生
当应用程序接收到鼠标键盘发送的事件后 窗口服务器将事件数据放到合适的应用程序事件队列中
应用程序对象从事件队列中读取事件数据 转发给用户界面对象(如按钮) 就出发了程序代码
如果程序改变了界面中的数据 界面就会被重新绘制 然后应用程序继续检查他的事件队列 接收下一个事件
检查时间队列的过程以及动作组成了整个主程序的事件循环
当用户选择从菜单中退出时 NSApp接收到一个terminate:消息 终止进程 应用程序销毁所有对象
关于target和action
target是一个指向对象的指针
action就是一个消息
例如单击按钮时 按钮将action发送给他的target
action方法中的sender参数使得接受者知道是哪个控制发送的消息 sender中也会存储一些其他的消息
比如
BOOL isOn = [sender state];//查看按钮是否被勾选上
AppDelegate文件
最先执行applicationSupportsSecureRestorableState
再执行applicationDidFinishLaunching:(NSNotification *)aNotification
(void)applicationDidFinishLaunching:(NSNotification *)aNotification作为程序的入口 用于初始化
在程序结束的时候会调用applicationDidFinishLaunching
还声明了一个NSwindow*window 的XIB文件的IBOutlet输出变量 这就让AppDelegate可以直接对window做一些操作 比如说windows的背景颜色等
Assets.xcassets文件
主要对工程中使用的图片资源进行统一管理
例如AppIcon的图片资源就作为应用的安装图标
NSControl继承关系图
结构
NSResponder 是一个非正式协议的抽象类 里面主要是声明了各种响应键盘鼠标触摸板等事件的抽象方法 约定了是将响应的响应者链处理机制 也就是约束了大家处理这些事件该怎么处理
然后NSApplication,NSWindow,NSWindowController,NSView,NSViewController就是事件响应者 他们继承了NSResponder 他们具体分化去处理具体的事情 比如说NSView就是具体处理视图(例如button)接收到鼠标键盘消息时的反应 NSWindow就是处理winow消息的鼠标键盘消息时的反应 然后依次往下戏份 直到NSButton这种
所以上面这些大的类就是规定类大的方向 怎么去处理
NSResponder定义了事件相关的抽象接口 具体实现由子类NSView负责
NSControl实现了界面交互的Action Message事件处理。NSControl内部包括一个cell类来负责UI界面绘制和Action Message事件处理 对于直接继承自NSCiew的子类 界面绘制由空间自己完成
NSCell
NSCell可以理解为对 NSControl更细粒度的控制 大多数NSView子类控件并不是由NSView完成界面绘制和事件响应处理 而是内部的cell类完成
NSSlider
右边栏里勾选continuous则滚动条移动时会不断的发送action消息 如果不勾选则是在鼠标释放后才发送action消息
NSTextField
NSTextField类的实例文本框允许用户输入一行文字 可以设置:可编辑 不可编辑
Action
button需要绑定一个IBAction 在按下的时候就要调用这个action
对于button来说 他只需要绑定一个行为 -(IBAction)xxx:(id)sender; //这样点击这个按钮的时候就会发送这个消息
例如
- (IBAction)show:(id)sender;//可以用来表示一个show按钮的action事件
//然后实现
- (IBAction)show:(id)sender {
NSString *string = [_test stringValue];
[_lebel setObjectValue:[NSString stringWithFormat:@"%@ num:%d",string, [string length]]];
}
outLet
文本框就需要指定一个outLet 在输入后传数据给outLet对象
例如
@property (weak) IBOutlet NSTextField *test;
@property (weak) IBOutlet NSTextField *lebel;
//调用时
[_lebel setObjectValue:[NSString stringWithFormat:@"%@ num:%d",string, [string length]]];
快捷创建outLet和Action
右键按住按钮或者文本框什么的
lebel
@property (weak) IBOutlet NSTextField *lebel;
lebel.editable = NO;
lebel.bordered = NO;
lebel.drawsBackground = NO;
setObjectValue:
NSString *string = [_test stringValue];//从_test绑定的文本框中获取输入的值
[_lebel setObjectValue:[NSString stringWithFormat:@"%@ num:%d",string, [string length]]];//通过setOBjectValue设置lebel要显示什么
help
很多类都有一个delegate成员变量
可以设置该变量指向一个helper对象
创建一个windows的代码
//myWindow.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
@interface myWindow : NSObject
@property(nonatomic,strong) NSWindow* myWindow;
-(IBAction)showWindowAction:(id)sender;
@end
NS_ASSUME_NONNULL_END
//myWindow.m
#import "myWindow.h"
@implementation myWindow
-(NSWindow*)myWindow
{
NSRect fram = CGRectMake(0,0, 200, 200);//设置位置和长宽
NSUInteger style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask;
NSWindow *window = [[NSWindow alloc]initWithContentRect:fram styleMask:style backing:NSBackingStoreBuffered defer:YES];
//sbacking 窗口绘制的缓存模式 defer表示延迟创建还是立即创建
window.title = @"New Create Window";
return window;
}
-(IBAction)showWindowAction:(id)sender
{
//窗口显示
[self.myWindow makeKeyAndOrderFront:self];
//窗口居中
[self.myWindow center];
}
@end
关于什么是keyWindow
获取activeWindow的名字
NSDictionary *activeApp = [[NSWorkspace sharedWorkspace] activeApplication];
NSLog(@"Active application is: %@", (NSString *)[activeApp objectForKey:@"NSApplicationName"]);
delegate和viewController的区别
AppDelegate是什么
OC应用程序是一个不断循环的程序
而AppDelegate是在不断循环的程序和我们的代码之间进行通讯
AppDelegate对象是作为Application对象的委托属性
主要作用是使我们有机会在每次应用程序状态更改时做出反应
AppDelegate protocol可选方法
application(UIApplication, didFinishLaunchingWithOptions: Dictionary)
这是第一个要执行的方法。调用它是为了让我们知道基本对象已被实例化,并且该应用已准备就绪。我们可以在此方法中编写准备应用程序所需的所有代码,例如声明初始值,创建或打开数据库,检查当前设置等。
applicationWillResignActive(UIApplication)
当应用程序不活动时通常由于传入呼叫或消息而调用此方法。
applicationDidEnterBackground(UIApplication)
关闭应用程序(移至后台)时调用此方法。
applicationWillEnterForeground(UIApplication)
在应用再次激活之前调用此方法。
applicationDidBecomeActive(UIApplication)
在启动应用程序以及从非活动状态恢复时调用此方法。
applicationWillTerminate(UIApplication)
在终止应用程序之前调用此方法。当系统决定终止应用程序时,通常会发生此状态,因为它需要其他应用程序的内存或应用已被用户终止。
MVC
M:model模型,一个程序需要处理的数据
V:view视图,就是用户界面,由窗口和视图组成
C:controller,控制器,在接受数据或者接受到视图行为后,对数据进行处理和视图进行变化的控制器对象
也就是说model和view是不会相互链接的,所以中间就需要controller来进行中间传输和处理
优点在于数据传输过来 通过controller的逻辑进行处理,作出相对应的反应,这个逻辑是可以重复多用的,
App生命周期
App载入会先调用loadView方法或载入IB中创建的初始界面的方法,将视图载入到内存中
window生命周期
View的生命周期
(view从xib右键拉出来)VC init->view awakeFromNib->VC viewDidLoad->view drawRect
(通过代码init alloc)
首先调用initWithFrame(如果是IB创建的会对view对象archives 自动调用initWithFrame),所以想要对IB创建的view进行属性初始化配置可以调用awakeFromNib
awakeFromNib(IB会自动调用)
awakeFromNib是在一个nib文件中所有view对象都完成加载之后,会向文件中所有view对象发一个awakeFromNib消息
viewDidDisappear的时候会调用 removeFormSuperView
当调用removeFromSuperView的时候 会先判断SuperView是否为nil 如果不为nil 则superView 会将当前view release
initWithFram(手动调用)
目前测试的情况是,如果我自己实现了一个customView类型,然后重写initWithFrame,和awakeFromNib 将这个view在IB的inspect版面赋值给viewController的view的一个subView(customView),然后如果通过右键在viewController.mm文件中添加这个@property (strong) IBOutlet customView *cusView;
则在viewController init的时候会自动调用awakeFromNib来初始化属性(简单点说就是和IB做了关联就会调用awakeFromeNib)
如果不右键添加,而是自己手动添加一个@property (strong) customView *cusView;则需要在viewController的init方法里面调用_cusView = [[customView alloc]initWithFrame:NSMakeRect(0, 0, 30, 30)];
然后在initWithFrame里面初始化属性,
在加载viewController的时候并不会自动调用initWithFrame。需要手动调用
drawRect
This method is invoked during the display process to generate code that’s rendered by the window server into a raster image
主要是在view被绘制的时候
接受的参数是一个rectangle,这个rectangle是接受者自己的坐标系中需要被绘制的区域
viewDidLoad
此时只是view被加载了比如大小,层次结构等, 并不是view已经显示了,所以此时对view进行属性设置是没有问题的,
setNeedDispaly
延迟绘制
标记一个view需要被redisplay 然后在这个event loop结束的时候会redisplay
如果需要立即绘制就直接调用display
displayIfNeeded
立即绘制如果当前这个view已经被标记为需要redesplay,应该是前面已经调用过setNeedDispaly
viewWillLayoutSubviews
一般会在哪些情况下被系统自动调用
视图被加载时,视图发生旋转时,子试图尺寸发生更改时(比如UIButton的textView内的内容发生变化时,或者添加删除子视图),显示视图时,还有调用setNeedsLayout 或 layoutIfNeeded
关于中途接受到display消息的绘制起点:View Opacity
在调用display方法的时候 这个view会在view hierarchy中定位第一个会返回isOpacity为YES的view,从这个view开始向前绘制
内存问题
viewDidUnload
在发生内存警告的时候如果本视图不是当前屏幕上正在显示的视图的话, viewDidUnload将会被执行,本视图的所有子视图将被销毁,以释放内存,此时开发者需要手动对viewLoad、viewDidLoad中创建的对象释放内存。 因为当这个视图再次显示在屏幕上的时候,viewLoad、viewDidLoad 再次被调用,以便再次构造视图。
问题
IBOutlet是什么修饰符 被IBOutlet修饰的应该就是target 可以用来指向控件的指针
IBAction和void有区别吗
怎么删除控件:command+删除键
cell是什么
cell是一个控件的内部单元格