#import
跟 #include
有什么区别, @class
呢,#import ""
跟 #import <>
有什么区别#include
在C 语言中会引入一个头文件,但是可能出现交叉编译, #import
,在OC 中引入自己创建的头文件(#import ""
),或者系统框架(#import <>
),#import
不会出现交叉编译@class
的作用是告诉编译器有@class后面的内容是一个类名。只是告诉编译器存在这么一个类,类具体包含哪些方法,属性和变量的并没有告诉编译器。一般在类的头文件中使用 @class来引入其他类。#import<>
用于对系统文件的引用,编译器会在系统文件目录中去查找文件#import ""
用于对自定义的文件的引用,编译器首先回去用户目录下查找,然后去安装目录,最后去系统目录中查找文件。setter,getter
方法访问。所谓的懒加载指的是延迟创建对象,只有当需要的时候才创建对象。在真正开发的过程中其实懒加载就是重写 getter
方法。在getter
方法的内部,实现对象的创建,如果对象为 nil
才创建,如果不为nil
,直接返回对象。在真正使用懒加载时需要注意的是当第一次使用对象时,需要调用 self.
因为只有这样才能调用对应的 getter
方法,对象才会被创建。
CALayer
是图层类,本身可以显示的,但是不能响应事件。UIView
是iOS
系统中界面元素的基础,所有的界面元素都继承自它。事件的处理由它来执行,但是显示其实是由其对应的 layer
层来操作的,UIView
内嵌了一个layer
, layer
显示内容,UIView
本身增加了事件处理的功能。UIWindow
继承自 UIView
,主要的作用是作为窗口呈现其他的视图。而且一个应用程序一般情况下只有一个窗口。id
是任意对象类型的,不能表示基本类型。id
类型是通用指针类型,因为通过指针,也就是内存地址来引用对象,所以可以将任意对象赋值给id
类型的对象。返回id
类型值的方法是返回指向内存中某对象的指针。然后可以将该值赋给任何对象变量(强制类型转换即可)。因为无论在哪里,对象总是携带它的isa
成员。所以即使将它存储在id
类型的通用对象变量中,也总是可以确定它的真实类型,id
是多态的一种体现
@property
有两个对应的词,一个是@synthesize
,一个是@dynamic
。如果@synthesize
和@dynamic
都没写,那么默认的就是@syntheszie var = _var
@synthesize
的语义是如果你没有手动实现setter
方法和getter
方法,那么编译器会自动为你加上这两个方法。@dynamic
告诉编译器:属性的setter
与getter
方法由用户自己实现,不自动生成。(当然对于readonly
的属性只需提供getter
即可)。@dynamic var
,然后你没有提供@setter
方法和@getter
方法,编译的时候没问题,但是当程序运行到 instance.var = someVar
,由于缺setter
方法会导致程序崩溃;或者当运行到 someVar = instance.var时
,由于缺getter
方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。@dynamic
可用于在分类中添加属性(需要用到 objc_getAssociatedObject
和objc_setAssociatedObject
函数)。runtime.h
中的objc_getAssociatedObject
和objc_setAssociatedObject
来访问和生成关联对象。例如为 NSObject
添加一个类目,分类中添加一个属性。代码如下所示:NSObject+Test.h
文件
#import
@interface NSObject (Test)
@property (nonatomic, strong) NSString *test;
@end
NSObject+Test.m
文件
#import “NSObject+Test.h"
#import
static const void *instanceNameKey = &instanceNameKey;
@implementation NSObject (Test)
@dynamic test;
- (NSString *)test
{
return objc_getAssociatedObject(self, instanceNameKey);
}
- (void)setTest:(NSString *)test
{
objc_setAssociatedObject(self, instanceNameKey, test, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
sizeof(...)
是运算符,在头文件中typedef
为unsigned int
,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。 sizeof
不能用来返回动态分配的内存空间的大小。实际上,用sizeof
来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。strlen(...)
是函数,要在运行时才能计算。参数必须是字符型指针(char *)
。当数组名作为参数传入时,实际上数组就退化成指针了。 NULL
。返回的长度大小不包括NULL
。 sizeof
操作符的结果类型是size_t
,它在头文件中 typedef
为unsigned int
类型。该类型保证能容纳实现所建立的最大对象的字节大小。 sizeof
是运算符,strlen
是函数。 sizeof
可以用类型做参数,strlen
只能用 char*
做参数,且必须是以'\0'
结尾的。sizeof
还可以用函数做参数,比如:short f()
; printf("%d\n",sizeof(f()))
; 输出的结果是 sizeof(short)
,即2 。 sizeof
的参数不退化,传递给strlen
就退化为指针了。 sizeof
计算过了 是类型或是变量的长度这就是sizeof(x)
可以用来定义数组维数的原因 char str[20]="0123456789"
; int a=strlen(str); // a=10
; int b=sizeof(str); //b=20
; strlen
的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小。 sizeof
后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof
是个操作符不是个函数。 sizeof
返回实际的大小,当适用一静态地空间数组, sizeof 归还全部数组的尺寸。sizeof
操作符不能返回动态地被分派了的数组或外部的数组的尺寸const
意味着"readonly"
,关键字const
什么含义? 下面的声明都是什么意思 ?const int a;
int const a;
const int *a;
int * const a;
int const * a const;
a
是一个常整型数a
是一个指向常整型数的指针 (也就是 ,整型数是不可修改的 ,但指针可以 )a
是一个指向整型数的常指 针 (也就是说 ,指针指向的整型数是可以修改的 ,但指针是不可修改的 )a
是一个指向常整型数的常指针 (也就是说 ,指针指向的整型数是不可修改的 ,同时指针也是不可修改的 )。欲阻止一个变量被改变 ,可以使用const
关键字。在定义该const
变量时 ,通常需要对它进 ⾏初始化, 因为以后就没有机会再去改变它了 const
, 也可以指定指针所指的数据为 const
, 或二者同时指定为 const
;const
可以修饰形参 ,表明它是一个输入参数 ,在函数内部不能改变其值 ;const
类型, 则表明其是一个常函数 ,不能修改类的成员变量 ;const
类型, 以使得其返回值不为“左值”nil,NSNULL,NULL
区别nil
定义一个实例(instance)为空, 指向OC中对象的空指针,是对 Objective-C id
对象赋空值,对于 Objective-C 集合类对象比如数组对象,字典对象,当我们不需要再使用他们的时候,对他们release
的同时最好也把他们赋值为nil
,这样确保安全性,如果不赋值nil
,可能导致程序崩溃NSNull
类定义了一个单例对象用于表示集合对象的空值。集合对象无法包含 nil作为其具体值,如NSArray、NSSet
和NSDictionary
。相应地,nil
值用一个特定的对象NSNull
来表示。NSNull
提供了一个单一实例用于表示对象属性中的的nil
值。默认的实现方法中,dictionaryWithValuesForKeys:
和setValuesForKeysWithDictionary:
自动地将NSNull1
和nil
相互转换,因此您的对象不需要进行NSNull
的测试操作。NULL
可以用在C 语言的各种指针上 ,在 Objective-C里,nil
对象被设计来跟NULL
空指针关联的。他们的区别就是nil
是一个对象,而 NULL
只是一个值。而且我们对于nil
调用方法,不会产生 `crash或者抛出异常。NSDictionary
是不可变的对象,NSMutableDictionary
是可变对象,可以进行添加和删除操作。是无序的排序的话可以这样做:
NSArray *myKeys = [myDictionary allKeys];
NSArray *sortedKeys = [myKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
id firstObject = [myDictionary objectForKey: [sortedKeys objectAtIndex:0]];
keysSortedByValueUsingSelector/keysSortedByValueUsingComparator
通过使用指定SEL
或NSComarator
来对allKeys
进行排序,然后通过objectsForKeys
取出排序后的键-值(key-values)对。
new/delete
势必会造成内存空间的不连续 ,从而造成大量的碎片 ,使程序效率降低。对于栈来讲 ,则不会存在这个问题 ,因为栈是先进后出的队列 ,他们是如此的一一对应 ,以至于永远都不可能有一个内存块从栈中间弹出malloc, calloc, realloc
等分配内存的函数分配得到的就是在堆上。浅层复制:只复制指向对象的指针 ,而不复制引用对象本身。
深层复制:复制引用对象本身。
意思就是说有个A对象,复制一份后得到A_copy对象后,对于浅复制来说,A和A_copy指向的是同一 个内存资源,复制的只不过是一个指针,对象本身资源还是只有一份,那如果我们对A_copy执行了修改操作,那么发现A引用的对象同样被修改。
深复制就好理解了 ,内存中存在了两份独立对象本身。
深浅拷贝前提是:是实现 NSCopying或者NSMutableCopying 协议。
深拷贝则对对象本身复制,同时对对象的属性也进行复制。
浅拷贝只是复制对象本身,对象的属性和包含的对象不做复制。
Foundation框架支持复制的类,默认是浅拷贝。其中对 Foundation中不可变的对象进行copy时作用相当于 retain。而如果是 mutablecopy时,无论对象是否可变,副本是可变的,并且实现了真正意义上的 copy。如果对可变对象进行copy,副本对象是不可变的,同样是真正意义上的 copy。
readwrite
,readonly
, assign
,retain
, copy
,nonatomic
属性的作用@property
是一个属性访问声明,扩号内支持以下几个属性
1. getter=getterName
,setter=setterName
,设置 setter
与getter
的方法名
2. readwrite
,readonly
,设置可供访问级别
3. assign
,setter
方法直接赋值, 不进行任何retain
操作 ,为了解决原类型与环循引用问题
4. retain
,setter
方法对参数进行release旧值再 retain
新值, 所有实现都是这个顺序 (CC上有相关资料 )
5. copy
,setter
方法进行copy
操作,与 retain
处理流程一样, 先旧值release
,再 copy
出新的对象, retainCount
为1。这是为了减少对上下文的依赖而引入的机制。 copy
是在不希望a 和b共享一块内存时会使用到。 a和 b各自有自己的内存。
6.nonatomic
, 非原子性访问, 不加同步,多线程并发访问会提高性能。注意 ,如果不加此属性 ,则默认是两个访问方法都为原子型事务访问。锁被加到所属对象实例级。atomic
和nonatomic
用来决定编译器生成的 getter和setter 是否为原子操作。在多线程环境下 ,原子操作 是必要的 ,否则有可能引起错误的结果。
@property
中属性retain,copy,assgin
的含义分别是什么?有什么区别?将其转换成get/set
方法怎么做?有什么注意事项?assign
: 简单赋值,不更改索引计数( Reference Counting)。使用assign
对基础数据类型 (NSInteger
,CGFloat
)和C数据类型(int
, float
, double
, char
, 等等)copy
: 建立一个索引计数为 1的对象,然后释放旧对象。使用copy
对 NSString
retain
:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为 1。使用retain
对其他 NSObject
和其子类
retain
表示持有特性,setter
方法将传入参数先保留,再赋值,传入参数的 retaincount
会+1
- (void)setInstance:(id)instance{
if (_instance != instance) {
[_instance release];
_instance = [instance retain];
}
}
copy
表示赋值特性,setter
方法将传入对象复制一份;需要完全一份新的变量时- (void)setInstance:(id)instance{
if (_instance != instance) {
[_instance release];
_instance = [instance copy];
}
}
assign
是赋值特性,setter
方法将传入参数赋值给实例变量;仅设置变量时- (void)setInstance:(id)instance{
if (_instance != instance) {
_instance = instance;
}
}
在使用NSMutableDictionary
的时候经常会使用setValue: forKey:
与setObject: forKey:
,他们经常是可以交互使用的,代码中经常每一种的使用都有。
他们二者的区别就是
1. setObject:forkey:
中 value
是不能够为nil
的,不然会报错。setValue: forKey:
中value
能够为nil
,但是当value
为nil
的时候,会自动调用 removeObject:forKey:
方法
2. setValue: forKey:
中 key
的参数只能够是NSString
类型,而setObject: forKey:
的可以是任何类型
3. setObject:forKey:
方法NSMutabledictionary
特有的 ,而setValue: forKey:
方法是KVC(键-值编码)的主要方法。
不要在滚动视图使用cornerRadius
或者mask
,添加
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
采取预先生成圆角图片,并缓存起来这个方法才是比较好的手段。预处理圆角图片可以在后台处理,处理完毕后缓存起来,再在主线程显示,这就避免了不必要的离屏渲染了。