‘壹’ ios 怎么设置一个全局的变量
方法1:使用静态变量 (不推荐)
方法2: 使用singleton pattern
方法3:把全局变量设置到AppDelegate中
例: 定义和使用一个全局变量"isLogin"
AppDelegate.h
@interface AppDelegate :UIResponder <UIApplicationDelegate>
@property (strong,nonatomic)UIWindow *window;
@propertyBOOL isLogin;
@end
AppDelegate.m
@implementation AppDelegate
@synthesize window =_window;
@synthesize isLogin;
@end
那么在其他的class里,则可以通过下列代码调用全局变量
AppDelegate *delegate=(AppDelegate*)[[]delegate];
delegate.isLogin=YES;
‘贰’ ios class 怎么引入类
选择File - New - File - ios - cocoatouch - Objective-C class(MAC开发同理),并且填写继承的父类,即创建出类。 引用创建的类仅需#import “你要引用的类名.h”
‘叁’ ios protocal和class的区别
是Protocol吧?
Protocol:协议(Protocol)将两个继承关系很远的类联系起来。
Class:
到目前为止,我们已经知道了对应于方法的SEL数据类型,和SEL同样在Objective-C里面我们不仅仅可以使用对应于方法的SEL,对于类在
Objective-C也为我们准备了类似的机制,Class类型。当一个类被正确的编译过后,在这个编译成功的类里面,存在一个变量用于保存这个类的信
息。我们可以通过一个普通的字符串取得
这个Class,也可以通过我们生成的对象取得这个Class。Class被成功取得之后,我们可以把这个Class当作一个已经定义好的类来使用它。这
样的机制允许我们在程序执行的过程当中,可以Class来得到对象的类,也可以在程序执行的阶段动态的生成一个在编译阶段无法确定的一个对象。
因为Class里面保存了一个类的所有信息,当然,我们也可以取得一个类的超类。关于Class类型,具体的使用格式如下:
1Class变量名=[类或者对象class];
2Class变量名=[类或者对象superclass];
3Class变量名=NSClassFromString(方法名字的字符串);
4NSString*变量名=NSStringFromClass(Class参数);
第一行代码,是通过向一个类或者对象发送class消息来获得这个类或者对象的Class变量。
第二行代码,是通过向一个类或者对象发送superclass消息来获得这个类或者对象的超类的Class变量。
第三行代码,是通过调用NSClassFromString函数,并且把一个字符串作为参数来取得Class变量。这个在我们使用配置文件决定执行的时候的类的时候,NSClassFromString给我们带来了极大的方便。
第四行代码,是NSClassFromString的反向函数NSStringFromClass,通过一个Class类型作为变量取得一个类的名字。
当我们在程序里面通过使用上面的第一,二或者第三行代码成功的取得一个Class类型的变量,比如说我们把这个变量名字命名为myClass,那么我们在
以后的代码种可以把myClass当作一个我们已经定义好的类来使用,当然我们可以把这个变量作为参数传递到其他的方法当中让其他的方法动态的生成我们需
要的对象。
‘肆’ ios 怎么调用分类里面的方法
ios category类别的使用
Objective-C提供了一个非常灵活的类(Class)扩展机制-类别(Category)。类别用于对一个已经存在的类添加方法(Methods)。你只需要知道这个类的公开接口,不需要知道类的源代码。需要注意的是,类别不能为已存在的类添加实例变量(Instance Variables)。
类别的基本语法如下:
@interface ClassName(CategoryName)
//method declarations
@end
@interface 类名(类别名)
类别方法申明
@end
注意几点:
1.现有类的类名位于 @interface之后
2.括号中是类别的名称(只要名称唯一,可以添加任意多的类别)
3.类别没有实例变量部分
类别的语法与类的语法非常相似。类别的方法就是类的方法。类别的定义可以放在一个单独的文件中("类别名.h"), 也可以放在一个已存在的类的定义文件中(.h文件)。类别的实现则可放在一个单独的“类别名.m”文件中,或另一个类的实现文件中。这点也与类的定义相似。因为类别的方法就是类的方法,所以类别的方法可以自由引用类的实例变量(无论公有或私有)。
子类(subclassing)是进行类扩展的另一种常用方法。与子类相比,类别最主要的优点是:系统中已经存在的类可以不需修改就可使用类别的扩展功能。例如,假设系统中存在一个类A;另外一个类B中定义了一个类A类型的实例变量,并包含了类A的头文件“#import <A.h>"。假设一段时间后,需要对类A扩展几个新的方法。如果用子类,就需要创建一个子类A-1。如果类B想要使用类A的新方法,就要进行如下修改:1) 将包含的头文件改为"#import<A-1.h>"; 2)将所有用到的类A对象改为类A-1的对象。可以想象,如何有很多类需要用到类A的新功能(比如类A是iOS中的类UIViewController),随着系统的升级(iOS从1.0到5.0),你的程序需要不停地进行这种繁琐地修改。如果使用类别,即使类A升级了,系统中其它的类可以不需任何修改,直接就可以调用类A的新方法。
类别的第二大优点是实现了功能的局部化封装。类别定义可以放在一个已存在的类(类A)的定义文件中(.h)。这意味着这个类别只有在类A被引用的前提下才会被外部看到。如果另一个类(类B)不需要用到类A的功能(没有包含类A的.h文件),也就不会看到依附类A存在的类别。iOS SDK中广泛运用这种类别定义法来封装功能。例如,在 UINavigationController.h中定义了专为UINavigationController扩展的UIViewController类别:
@interface UIViewController (UINavigationControllerItem)
@property(nonatomic,readonly,retain) UINavigationItem *navigationItem;
@property(nonatomic,readonly,retain) UINavigationController *navigationController;
......
@end
如果一个类不引用UINavigationController.h,也就不会看到navigationItem和navigationController这两个性质申明(declared property)。
类别的另一个优点是轻巧(light-weight)。很多时候,对已存在的类所需的扩展仅仅是几个新方法。这时,用类别避免了在系统中留下很多非常短小的“微”子类,使程序更加紧凑。
归纳:
1、实现类别
同实现类相似,实现方法即可
2、 类别的局限性
1.类别不能添加新的实例变量
2.命名冲突,如果类别中方法和类中已有方法同名,则类别具有更高优先级
3 类别的作用
1.将类的实现分散到多个不同文件或多个不同框架中
2.创建私有方法的前向引用
3.向对象添加非正式协议
4 利用类别分散实现
利用类别可以将类的方法分散到多个源文件中
特别指出的是:类别可以访问其继承的类的实例变量
在使用一个方法时,对象的方法是在接口中声明、父类中声明、还是类别中声明并不重要
类别不仅可以分散实现到不同源文件,也可跨框架
5、 使用类别创建前向引用
虽然可以实现未声明的方法,但是编译器会提出警告
通过类别可以提供声明,而且,声明的方法不必要一定在类别的实现中实现,也可以在类的实现中实现
6、 非正式协议和委托类别
委托(delegage)是一种对象,另一个类的对象会要求委托对象执行它的某些操作
委托对象接受其它对象对它的特定方法的调用
其实就是委托对象必须实现别的对象调用的方法,与接口类似
7、 ITunesFinder项目
8 、委托和类别
委托和类别有什么关系?委托强调类别的另一种应用:被发送给委托对象的方法可以声明为一个NSObject的类别
创建一个NSObject的类别称为“创建一个非正式协议”
9、 响应选择器
选择器只是一个方法名称,可以使用@selector()预编译指令指定选择器,其中方法名位于圆括号中,但它以OC运行时使用的特殊方式编码,以快速执行查询
NSObject提供了一个respondsToSelector的方法,询问对象以确定其是否实现某个特定消息
10、 选择器的其他应用
选择器可以被传递,可以作为方法参数,甚至可以作为实例变量存储
‘伍’ ios class 怎么引入类
选择File - New - File - ios - cocoatouch - Objective-C class(MAC开发同理),并且填写继承的父类,即创建出类。 引用创建的类仅需#import “你要引用的类名.h”。
‘陆’ ios 怎么动态向已有类添加属性
在ios运行过程中,有几种方式能够动态的添加属性。
1-通过runtime动态关联对象
主要用到了objc_setAssociatedObject,objc_getAssociatedObject以及objc_removeAssociatedObjects
//在目标target上添加关联对象,属性名propertyname(也能用来添加block),值value
+ (void)addAssociatedWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
id property = objc_getAssociatedObject(target, &propertyName);
if(property == nil)
{
property = value;
objc_setAssociatedObject(target, &propertyName, property, OBJC_ASSOCIATION_RETAIN);
}
}
//获取目标target的指定关联对象值
+ (id)getAssociatedValueWithTarget:(id)target withPropertyName:(NSString *)propertyName {
id property = objc_getAssociatedObject(target, &propertyName);
return property;
}
优点:这种方式能够使我们快速的在一个已有的class内部添加一个动态属性或block块。
缺点:不能像遍历属性一样的遍历我们所有关联对象,且不能移除制定的关联对象,只能通过removeAssociatedObjects方法移除所有关联对象。
2-通过runtime动态添加Ivar
主要用到objc_allocateClassPair,class_addIvar,objc_registerClassPair
//在目标target上添加属性(已经存在的类不支持,可跳进去看注释),属性名propertyname,值value
+ (void)addIvarWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
if (class_addIvar([target class], [propertyName UTF8String], sizeof(id), log2(sizeof(id)), "@")) {
YYLog(@"创建属性Ivar成功");
}
}
//获取目标target的指定属性值
+ (id)getIvarValueWithTarget:(id)target withPropertyName:(NSString *)propertyName {
Ivar ivar = class_getInstanceVariable([target class], [propertyName UTF8String]);
if (ivar) {
id value = object_getIvar(target, ivar);
return value;
} else {
return nil;
}
}
优点:动态添加Ivar我们能够通过遍历Ivar得到我们所添加的属性。
缺点:不能在已存在的class中添加Ivar,所有说必须通过objc_allocateClassPair动态创建一个class,才能调用class_addIvar创建Ivar,最后通过objc_registerClassPair注册class。
3-通过runtime动态添加property
主要用到class_addProperty,class_addMethod,class_replaceProperty,class_getInstanceVariable
//在目标target上添加属性,属性名propertyname,值value
+ (void)addPropertyWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
//先判断有没有这个属性,没有就添加,有就直接赋值
Ivar ivar = class_getInstanceVariable([target class], [[NSString stringWithFormat:@"_%@", propertyName] UTF8String]);
if (ivar) {
return;
}
/*
objc_property_attribute_t type = { "T", "@\"NSString\"" };
objc_property_attribute_t ownership = { "C", "" }; // C =
objc_property_attribute_t backingivar = { "V", "_privateName" };
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
class_addProperty([SomeClass class], "name", attrs, 3);
*/
//objc_property_attribute_t所代表的意思可以调用getPropertyNameList打印,大概就能猜出
objc_property_attribute_t type = { "T", [[NSString stringWithFormat:@"@\"%@\"",NSStringFromClass([value class])] UTF8String] };
objc_property_attribute_t ownership = { "&", "N" };
objc_property_attribute_t backingivar = { "V", [[NSString stringWithFormat:@"_%@", propertyName] UTF8String] };
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
if (class_addProperty([target class], [propertyName UTF8String], attrs, 3)) {
//添加get和set方法
class_addMethod([target class], NSSelectorFromString(propertyName), (IMP)getter, "@@:");
class_addMethod([target class], NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]), (IMP)setter, "v@:@");
//赋值
[target setValue:value forKey:propertyName];
NSLog(@"%@", [target valueForKey:propertyName]);
YYLog(@"创建属性Property成功");
} else {
class_replaceProperty([target class], [propertyName UTF8String], attrs, 3);
//添加get和set方法
class_addMethod([target class], NSSelectorFromString(propertyName), (IMP)getter, "@@:");
class_addMethod([target class], NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]), (IMP)setter, "v@:@");
//赋值
[target setValue:value forKey:propertyName];
}
}
id getter(id self1, SEL _cmd1) {
NSString *key = NSStringFromSelector(_cmd1);
Ivar ivar = class_getInstanceVariable([self1 class], "_dictCustomerProperty"); //basicsViewController里面有个_dictCustomerProperty属性
NSMutableDictionary *dictCustomerProperty = object_getIvar(self1, ivar);
return [dictCustomerProperty objectForKey:key];
}
void setter(id self1, SEL _cmd1, id newValue) {
//移除set
NSString *key = [NSStringFromSelector(_cmd1) :NSMakeRange(0, 3) withString:@""];
//首字母小写
NSString *head = [key substringWithRange:NSMakeRange(0, 1)];
head = [head lowercaseString];
key = [key :NSMakeRange(0, 1) withString:head];
//移除后缀 ":"
key = [key :NSMakeRange(key.length - 1, 1) withString:@""];
Ivar ivar = class_getInstanceVariable([self1 class], "_dictCustomerProperty"); //basicsViewController里面有个_dictCustomerProperty属性
NSMutableDictionary *dictCustomerProperty = object_getIvar(self1, ivar);
if (!dictCustomerProperty) {
dictCustomerProperty = [NSMutableDictionary dictionary];
object_setIvar(self1, ivar, dictCustomerProperty);
}
[dictCustomerProperty setObject:newValue forKey:key];
}
+ (id)getPropertyValueWithTarget:(id)target withPropertyName:(NSString *)propertyName {
//先判断有没有这个属性,没有就添加,有就直接赋值
Ivar ivar = class_getInstanceVariable([target class], [[NSString stringWithFormat:@"_%@", propertyName] UTF8String]);
if (ivar) {
return object_getIvar(target, ivar);
}
ivar = class_getInstanceVariable([target class], "_dictCustomerProperty"); //basicsViewController里面有个_dictCustomerProperty属性
NSMutableDictionary *dict = object_getIvar(target, ivar);
if (dict && [dict objectForKey:propertyName]) {
return [dict objectForKey:propertyName];
} else {
return nil;
}
}
优点:这种方法能够在已有的类中添加property,且能够遍历到动态添加的属性。
缺点:比较麻烦,getter和setter需要自己写,且值也需要自己存储,如上面的代码,我是把setter中的值存储到了_dictCustomerProperty里面,在getter中再从_dictCustomerProperty读出值。
4-通过setValue:forUndefinedKey动态添加键值
这种方法优点类似property,需要重写setValue:forUndefinedKey和valueForUndefinedKey:,存值方式也一样,需要借助一个其它对象。由于这种方式没通过runtime,所以也比较容易理解。
‘柒’ iOS中import和include,class的区别
1。import和include都是包含某个文件
2.import可以防止重复包含
3.class是声明有这个类,具体怎么实现没包括
‘捌’ ios为什么class
#import是引入头文件和类库的,@class适用于前向声明一个类。但是没有引入,需要用这个类时,还是如要把这个类的头文件给improt进来的
‘玖’ iOS开发中#import,include和@class的区别解析
#import与@class的区别
1.import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。
2.在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
3.在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。
4.如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。
所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来.
#import和#include的区别
当我们在代码中使用两次#include的时候会报错:因为#include相当于拷贝头文件中的声明内容,所以会报重复定义的错误
但是使用两次#import的话,不会报错,所以他可以解决重复导入的问题,他会做一次判断,如果已经导入一次就不导入了