iOS 何为bounds,何为frame

关于frame

  • frame是三个复合属性,由center、bounds和transform共同计算而来。
  • transform退换,frame会受到震慑,但是center和bounds不会遭到震慑。也便是你使用transform来缩放,bounds是不会变的。那么由center和bounds总计获得的frame是永世保持transform为identity时的情事。那也是为什么把transform设为identity后,view会回归到先前时代状态。

小编方今梳理iOS知识系统,布署写四个名叫“重识iOS”的数不尽,内容出自平日的就学笔记,参谋了一些篇章和书籍,融合本人的驾驭以记录。招待交流指正。本文为率先篇:Category。

小编近期梳理iOS知识系统,布置写一个名叫“重识iOS”的两种,内容出自平常的求学笔记,参照他事他说加以考察了一些稿子和本本,融合本身的知道以记录。招待调换指正。本文为第二篇:Property。

iOS中经过改动view视图对象的transform属性就会到位对view的移位,缩放,旋转那样的2D变化transform质量的等级次序CGAffineTransform是一种结构体类型

从先导iOS,小编就径直不了然bounds和frame之间的区分。真的很稀奇,无论看某个有关的blog。

关于transform的计算

当您采用view.transform = xxx时候,它毕竟是怎么起效果的?首先,它是四个矩阵,使用矩阵乘法,对view的frame进行转变,获得新的转变,那么这些逻辑是如何的?

  • 它是指向父视图坐标的。
  • 它是本着view的启幕宗旨为坐标的:“初步”是指transform值为identity时的事态,即未有其余的缩放、平移或旋转;“中央”私下认可是view方块的着力,但其实是anchorPoint

那么viewA.transform = myTransform这样一段代码就等价于:

  1. 把父视图坐标系的原点移动到view的中坚,计算中央坐标系的frame,得到frame1:

CGRect frame1 = CGRectMake(-originalFrame2.size.width/2.0,-originalFrame2.size.height/2.0, originalFrame2.size.width, originalFrame2.size.height);
  1. 以坐标系退换后的frame(即centerFrame)总结,使用矩阵乘法应用transform,获得frame2:CGRect frame2 = CGRectApplyAffineTransform(frame2, myTransform)

  2. 再把结果转回原父视图坐标系,获得frame3:

CGRect frame3 = CGRectMake(frame2.origin.x + CGRectGetMidX(originalFrame), frame2.origin.y + CGRectGetMidY(originalFrame),frame2.size.width, frame2.size.height);

那般做的补益正是在缩放的时候,是本着view当前地点的,那样view的原点不会变动,也正是缩放只会生出缩放的功能,而不会时有发毕生移。假若使用父视图原点,frame为{10,20,100,100},缩放后改成{5,10,50,50},那么frame不仅仅变小了,也和原点更近了。

图片 1category

图片 2property

富含了6个可变的值和3个定值,组成了3*3的矩阵a,b,0 c,d,0 tx,ty,1修改了6个值中的某多少个,就足以兑现变形,实际中不会手动修改6个值,能够借助系统提供的API达成数值的变动rotation:旋转scale:缩放translation:位移

四个View要明确它的地点和分寸,那么就亟须驾驭它的 position,
即x,y的坐标,和它的长短,中度。那4个参数都以相对父视图来说的。大家在程序中为了钦命那多少个参数,使用的就是view
的 frame那本个性。

怎么计算多个frame之间的transform

给你四个view和多个目的frame,求叁个transform,使得把那个transform给view后,view的frame等于目的frame。

在管理动画的时候会用到。

因为缩放会潜濡默化平移,而活动却不会潜移暗化缩放,所以先平移到骨干和对象frame一致,然后缩放。

挪动的离开正是多个center的差值,缩放比例的便是多少个frame的边长之比。

即:

-(CGAffineTransform)transformFromRect:fromRect toRect:toRect{ CGAffineTransform moveTrans = CGAffineTransformMakeTranslation(CGRectGetMidX - CGRectGetMidX, CGRectGetMidY - CGRectGetMidY); CGAffineTransform scaleTrans = CGAffineTransformMakeScale(toRect.size.width / fromRect.size.width, toRect.size.height / fromRect.size.height); //右边先执行 return CGAffineTransformConcat(scaleTrans, moveTrans);}

熟谙设计方式的开辟人士应该都通晓装潢情势(Decorator),它是在不修改原代码的底子上开展扩充。iOS开采中category正是对装修格局的天下无双推行。

  • 简要介绍:属性是Objective-C的一项特征,用于卷入对象中的数据。这一风味能够令编写翻译器自动编写与质量相关的存取方法,並且保留为各样实例变量。
  • 实质:属性的精神是实例变量与存取方法的整合。@property = ivar + getter + setter

选择带Make的函数运算时都以依据未有变形前的极度地方

CGAffineTransformMakeRotation()``CGaffineTransformMakeScale()``CGAffineTransformMakeTranslation()

UIView * v = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 200, 200)];

何以选拔transform动画实际不是安装frame?

假若transform里含有了旋转,那么总结出来的frame就从不意义了,因为frame总是描述一个“放正的”方块,而旋转后的四方是出于无奈描述的。

但对此独有移动和缩放,用上述逻辑是能够总括的。笔者在做贰个过场动画的时候利用了那些,动画是相近系统相册那样从贰个小图逐步松手到全屏,所以您抱有的信息是贰个开始的frame,以那些为始发动画。

本人尝试了通过直接设置frame来试行动画,但意识效果不佳,因为动画即便有多个经过,但实在从动画一从头,frame就曾经修改了。就算向来设置frame,那么开端的时候,子视图就能够按变化后的frame来重新布局,并非跟随父视图一齐逐步转移

卡通是渲染展现上的样板,而实际的数值却是另一种样子,在core
animation里有模型树呈现树的区别。

举个例证:

图片 3设置frame的动画图片 4设置transform的动画

测验view是稻草黄,它有二个子视图是新民主主义革命:

-layoutSubviews{ innerView.frame = CGRectMake(10, 10, self.frame.size.width-20, self.frame.size.height-20);}

内部的view保持和父视图10的边距。所以看率先个卡通,在刚起始的时候,深黄铜色的view就产生了动画结束时的轻重缓急,而第二个卡通使用transform转换,其实layoutSubviews并不曾调用,但是却收获了想要的职能。貌似transform只是影响了view的渲染,并且是熏陶了全副的子视图数,仿佛把这几个view当做一张图片相同收缩了,而里边却不需求再行布局。

选用transform效果更加好,那么将在从三个初阶frame总结得到transform,使得赋值给view后,它正是到伊始frame的地点。所以就有了上边的transform总计。

Category的简介

Category是Objective-C
2.0之后加上的语言特征,category的显要功能是为已经存在的类增多方法

下边包车型客车函数是在历次更改的Transform属性基础之上继续更改

CGAffineTransformRotation()``CGAffineTranformScale()``CGAffineTransformTranslation()

恍如下面这样,极其轻巧。按理说只是明显view的职分的话只需求frame,大家在编制程序的时候也实在基本上只会用到frame,可是UIKit还给了叁本性格叫bounds,和frame非常类似,但实在它的功能实际不是改造作者的长久状态。而是改造自身的坐标系。大家驾驭自视图是参照父视图的坐标系来利用frame定位本身的,那么当父视图的bounds退换,那么子视图的参阅也变了,子视图的任务也会发生变化。

Category的结构

咱俩领略Objective-C中类和指标都以C结构,category的结构如下:

struct _category_t { const char *name; // 1 struct _class_t *cls; // 2 const struct _method_list_t *instance_methods; // 3 const struct _method_list_t *class_methods; // 4 const struct _protocol_list_t *protocols; // 5 const struct _prop_list_t *properties; // 6};
  1. name 主类的名字
  2. cls 要强大的类对象,编写翻译期没有值,运行期依据 name 对应到类对象
  3. instance_methods 实例方法列表
  4. class_methods 类方法列表
  5. protocols 完结的协商列表,有的时候用但真正支撑
  6. properties
    属性列表,能够定义属性,不能合成实例变量,可经过关系对象开展绑定,与守旧实例变量是两样东西。
  • 为已经存在的类增加方法(非常是为看不见源码的系统类)
  • 把类的完结分开在多少个不等的文书中,好处:
  1. 削减单个文件体积
  2. 意义分别
  3. 两个人共同开辟一个类
  4. 贯彻按需加载
  • 无法加多实例变量(可由此runtime关联对象)

注意:category能够增添属性,只是不可能自动合成实例变量

  • 艺术覆盖:与主类同名的章程优先级高于主类方法

注意:category并不是截然替换掉主类的同名方法,只是类的方法列表里会晤世多少个名字同样的法子,何况category的办法会排在本类方法的前方,运维时追寻方法遵照顺序,一旦找到就止住,也就涌出了所谓的办法覆盖

  • Category在 运营期决议
    。category无法加多实例变量,因为在运营期对象的内部存款和储蓄器布局已经规定,增加实例变量会破坏类的内部结构。

  • Extension在 编译器决议 。extension能够独立制造生成 .h
    文件,常写在主类 .m
    中作为类的一有些,一般用来遮掩类的私家新闻,必需有三个类的源码本事为其增进一个extension。

咱俩已经掌握category无法自动合成实例变量,可是能够经过runtime关联对象的措施来贯彻
settergetter

//.h文件#import "MyClass.h"@interface MyClass @property (nonatomic, copy) NSString *name;@end//.m文件#import "MyClass+Addition.h"static void *kNameKey = &kNameKey;@implementation MyClass /** * 设置关联对象* * @param 需要被关联的对象* @param key 关联对象的key 一般这样设置static char key;* @param value 被关联对象的属性,如果设置nil,就取消关联* @param policy 关联策略,相当于属性的内存管理语义*/- setName:(NSString *)name { objc_setAssociatedObject(self, kNameKey, name, OBJC_ASSOCIATION_COPY);}- (NSString *)name { return objc_getAssociatedObject(self, kNameKey);}@end//objc_setAssociatedObject第4个参数:策略的枚举typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) { OBJC_ASSOCIATION_ASSIGN = 0, //关联对象的属性是弱引用 OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, //关联对象的属性是强引用且关联对象不使用原子性 OBJC_ASSOCIATION_COPY_NONATOMIC = 3, //关联对象的属性是copy且关联对象不使用原子性 OBJC_ASSOCIATION_RETAIN = 01401, //关联对象的属性是copy且关联对象使用原子性 OBJC_ASSOCIATION_COPY = 01403 //关联对象的属性是copy且关联对象使用原子性};
  • 1.在类的 +load 方法中能够调用category里声称的方法吗?

能够,因为附加category到类的干活会先于 +load 方法的进行。

  • 2.类和category的 +load 方法调用顺序是何许的?

+load 的举办顺序是:先类,后category。而一一category的
+load进行种种是由编写翻译顺序决定的。

  • 3.关乎对象存在哪?怎么着存储?对象销毁时候什么管理涉及对象?

怀有的涉及对象都由 AssociationsManager 管理, AssociationsManager
里面是由叁个静态 AssociationsHashMap 来存款和储蓄全部的涉及对象的。

相当于把装有目标的涉嫌对象都设有四个大局 map 面。而 mapkey
是以此指标的指针地址, value 一个 AssociationsHashMap
,里面保存了事关对象的键值对。

runtime的灭相对象函数 objc_destructInstance
里面会咬定这几个指标有未有涉嫌对象,若是有,会调用
_object_remove_assocations 做涉嫌对象的清总管业。

参谋作品:

  • 深入精晓Objective-C:Category
  • objc category的秘密
  • 原子性: atomic / nonatomic
  • 读写权限: readwrite / readonly
  • 内部存款和储蓄器管理语义: assign / strong / copy / weak /
    unsafe_unretained
  • 方法名: getter=<name> / setter=<name>

CGAffineTransformInvert()

CGAffineTransformInvert()获取相反的机能

大家来看个例证:

atomic 与 nonatomic

问题:怎么样是原子性? 证实并比较atomic和nonatomic。
atomic是任何平安的啊?

  • 原子性:并发编制程序中保障其操作具有全部性,系统别的一些无法观望到中间步骤,只可以见到操作前后的结果。
  • atomic:原子性的,编写翻译器会通过锁定机制确定保障 settergetter
    的完整性。
  • nonatomic:非原子性的,不保障 settergetter 的完整性。
  • 区别:由于要力保操作完整,atomic 速度相当的慢,线程绝对安全;
    nonatomic 速度一点也不慢,不过线程不安全。 atomic
    亦不是纯属的线程安全,当多少个线程同时调用 settergetter
    时,就能够形成获取的值不一样。由于锁定机制开销非常的大,一般iOS开采中会使用
    nonatomic ,而macOS中使用 atomic 平常不会有总体性瓶颈。
  • 拓展:要想线程相对安全,将要动用 @synchronized
    同步锁。不过出于共同锁有等待操作,会骤降代码功能。为了兼顾线程安全和进级换代功效,可选取GCD并发队列张开优化创新。getter
    使用同步派发,setter 使用异步栅栏。

//同步锁- (NSString *)someString { @synchronized { return _someString; }}- setSomeString:(NSString *)someString { @synchronized { _someString = someString; }}//并发队列_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);- (NSString *)someString { __block NSString *localSomeString; dispatch_sync(_queue, ^{ localSomeString = _someString; }); return localSomeString;}- setSomeString:(NSString *)someString { dispatch_barrier_async(_queue, ^{ _someString = someString; });}

CGAffineTransformIdentity

常量CGAffineTransformIdentity 记录矩阵未有成形的早先时期6个值,
要是将此常量赋值给tansform属性的话,那么视图爆发过的全体变形效果都会消退,回到最早状态如: _views.transform = CGAffineTransformIdentity;

self.views.transform = CGAffineTransformRotate(self.views.transform, M_PI_4);self.views.transform = CGAffineTransformScale(self.views.transform, 1.1, 1.1);self.views.transform = CGAffineTransformTranslate(self.views.transform, 2, 3);

图片 5transform.gif

在iOS中还足以经过对视图对象view的图层属性layertransform性子做修改来达成部分3D成效layertransform品质的品类CATransform3D的构造体类型:struct CATransform3D { CGFloat m11, m12, m13, m14(); CGFloat m21, m22, m23; CGFloat m31, m32, m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。正直/负值都有意义); CGFloat m41, m42, m43, m44(); };3D矩阵详解

306C09A8-43B8-435F-B67D-14EC87168D68.png

readwrite 与 readonly

读写权限不写时默感到 readwrite 。一般可在 .h 里写成
readonly,只对外提供读取,在 .mextension中再设置为 readwrite
可进展写入。

//.h文件#import <Foundation/Foundation.h>@interface MyClass : NSObject@property (nonatomic, readonly, copy) NSString *name;@end//.m文件#import "MyClass.h"@interface MyClass()@property (nonatomic, readwrite, copy) NSString *name;@end

在历次改变的Transform属性基础之上继续转换

CATransform3DRotate(CATransform3D t, CGFloat angle, CGFloat x, CGFloat y, CGFloat z)CATransform3DScale(CATransform3D t, CGFloat sx, CGFloat sy, CGFloat sz)CATransform3DTranslate(CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz)

此地大家只设置了father view 的frame和son view的frame。结果如小编辈预料的。

内部存款和储蓄器管理语义

  • strong:表示针对并负有该对象。其修饰的对象引用计数会 +1
    ,该目的只要援用计数不为 0
    就不会销毁,强行置空能够销毁它。一般用来修饰对象类型、字符串和集合类的可变版本。
  • copy:与
    strong恍如,设置方法会拷贝一份别本。一般用来修饰字符串和集结类的不可变版以及block
  • weak:表示指向但不具有该对象。其修饰的靶子引用计数不会扩张,属性所指的对象销毁时属性值会清空。ARC景况下一般用来修饰也许会挑起循环援引的目的,delegate
    xib 控件用 weak 修饰。
  • assign:首要用来修饰基本数据类型,如 NSItegerCGFloat
    等,那一个数值首要设有于栈中。
  • unsafe_unretained:与weak
    类似,但是销毁时不活动清空,轻易造成野指针。

  • 同样:用于修饰表示全体关系的指标。
  • 不同:strong 复制是多个指针指向同一个地址,而 copy
    的复制是历次会在内部存储器中复制一份对象,指针指向分歧的地点。NSString
    NSArrayNSDictionary 等不可变对象用 copy
    修饰,因为有希望传播二个可变的版本,此时能担保属性值不会受外部影响。
  • 注意:若用 strong 修饰
    NSArray,当数组接收七个可变数组,可变数组若爆发变化,被修饰的天性数组也会产生变化,约等于说属性值轻松被曲解;若用
    copy 修饰
    NSMutableArray,当试图修改属性数组里的值时,程序会崩溃,因为数组被复制作而成了七个不可变的本子。

  • 同等:都不是强引用。
  • 不同点:weak 援用的目的被销毁时,
    指针会被电动清空,不再指向销毁的靶子,不会发生野指针错误;
    unsafe_unretain 援引的对象被灭绝时, 指针并不会被活动清空,
    照旧指向销毁的靶子,很轻巧生出野指针错误: EXC_BAD_ACCESS
    assign 修饰基本数据类型,内设有栈上由系统自动回收。

带Make 依据初始值转变

CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz)CATransform3DMakeTranslation(CGFloat tx, CGFloat ty, CGFloat tz)

图片 6transform3D.gif

接下去大家转移父视图的bounds,看看会产生什么。代码如下所示:

储存方法名

getter=<name>setter=<name><>
中为艺术名,通过此特质来钦定期存款取方法的称谓。

//.h文件@interface MyClass : NSObject@property (nonatomic, assign, getter=isOn) BOOL on;@end//.m文件@implementation MyClass- isOn { return self.on;}@end

property有私下认可设置。

  • 骨干数据类型:atomic, readwrite, assign
  • 对象类型:atomic, readwrite, strong
  • 注意:考虑到代码可读性以及日常代码修改频率,标准的编码风格中爱抚词的一一是:原子性、读写权限、内部存款和储蓄器管理语义、getter/getter

大家已经精晓 @property
会使编写翻译器自动编写访问这么些属性所需的秘籍,此进度在编写翻译期完毕,称为
自动合成 (autosynthesis)。与此相关的还会有四个重大词:@dynamic
@synthesize

  • @dynamic:告诉编写翻译器不要自行创造达成属性所用的实例变量,也无须为其创立存取方法。就算编写翻译器开采未有概念存取方法也不会报错,运维期会导致崩溃。
  • @synthesize:在类的贯彻文件里能够由此 @synthesize
    钦定实例变量的称号。
  • 注意:在Xcode4.4之前,@property 配合
    @synthesize使用,@property 担当表明属性,@synthesize
    负担让编写翻译器生成 关节炎划线前缀的实例变量并且自动生成 setter
    getter方法。Xcode4.4之后 @property 获得压实,直接一并代替他了
    @synthesize 的工作。

参考:

  • 书本:《Effective Objective-C 2.0:编写高素质iOS与OS
    X代码的伍12个有效办法》
    CGRect fatherViewBounds = fatherView.bounds;
    fatherViewBounds.origin.x -= 10;
    fatherViewBounds.origin.y -= 10;
    fatherView.bounds = fatherViewBounds;

6E68A542-1F4C-4732-B236-040DEC013EAB.png

结果正是father view的具有子view(son
view、label)都在x、y上偏移了12个point。

何以会这么?

私下认可情状下当前view的坐标轴即bounds实在左上角(0,
0)的地点。若是大家把bounds的x,y退换,就像是上边那样,那么原本的(0,
0)就改为了(-10, -10)。那么father view 的坐标轴就成为了上面那样

050AC34D-9D16-411E-AE41-DE519FD22075.png

相当于说当咱们退换bounds的时候,大家转移的是它的坐标种类。受影响的是参照它来恒定的子视图。

不知道本身有未有讲清楚

发表评论

电子邮件地址不会被公开。 必填项已用*标注