添加了新的类 UIAlertController 和 UIAlertAction 来取代曾经的 UIAlertView 和 UIActionSheet,感觉警告窗口的结构更容易理解了,使用起来也更简便。但是曾经用 Xcode 5 创建过 iOS 7程序在iOS 8 设备上运行就会出现各种问题。我清晰地记得刚刚升级 iOS 8 后连微信的警示 *** 作表也出了问题,猜测可能是因此而起的。
下面来看看UIAlertController 和 UIAlertAction 用法:
1 最简单的提醒视图:
这里我们实现一个最简单的提醒视图,包含1个标题,1行信息,1个按键,按下按键后,什么都不发生:
[objc] view plain copy
- (IBAction)doAlert:(id)sender {
// 准备初始化配置参数
NSString title = @"Alert Button Selected";
NSString message = @"I need your attention NOW!";
NSString okButtonTitle = @"OK";
// 初始化
UIAlertController alertDialog = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
// 创建 *** 作
UIAlertAction okAction = [UIAlertAction actionWithTitle:okButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction action) {
// *** 作具体内容
// Nothing to do
}];
// 添加 *** 作
[alertDialog addAction:okAction];
// 呈现警告视图
[self presentViewController:alertDialog animated:YES completion:nil];
}
进入程序后,点击“Alert Me!”按钮可触发这个提醒框,如图所示:
从代码可以看出,新的API更加符合逻辑,有种需要什么就加什么的感觉。
2 多个按键的提醒视图
这里我们实现一个最简单的提醒视图,包含1个标题,1行信息,3个按键,按下按键后,标签显示按下的按键名称:
[objc] view plain copy
- (IBAction)doMultiButtonAlert:(id)sender {
// 准备初始化配置参数
NSString title = @"Alert Button Selected";
NSString message = @"I need your attention NOW!";
NSString okButtonTitle = @"OK";
NSString neverButtonTitle = @"Never";
NSString laterButtonTitle = @"Maybe Later";
// 初始化
UIAlertController alertDialog = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
// 分别3个创建 *** 作
UIAlertAction laterAction = [UIAlertAction actionWithTitle:laterButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction action) {
// 普通按键
selfuserOutputtext = @"Clicked 'Maybe Later'";
}];
UIAlertAction neverAction = [UIAlertAction actionWithTitle:neverButtonTitle style:UIAlertActionStyleDestructive handler:^(UIAlertAction action) {
// 红色按键
selfuserOutputtext = @"Clicked 'Never'";
}];
UIAlertAction okAction = [UIAlertAction actionWithTitle:okButtonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction action) {
// 取消按键
selfuserOutputtext = @"Clicked 'OK'";
}];
// 添加 *** 作(顺序就是呈现的上下顺序)
[alertDialog addAction:laterAction];
[alertDialog addAction:neverAction];
[alertDialog addAction:okAction];
// 呈现警告视图
[self presentViewController:alertDialog animated:YES completion:nil];
}
3个按键分别代表了3种不同类型的按键,分别是默认按键(普通)、销毁按键(红色)和取消按键(粗体)。从代码看其实就是在上一个的基础上加了3个 UIAlertAction 而已,然后分别设置不同的 style,效果如下:
3 带输入框的提醒视图
如何添加输入框呢?新的 iOS 8 提供了相应的接口,使增加输入框就像增加按键方法一样简单。这里还是在第1个方法的基础上改动。
[objc] view plain copy
- (IBAction)doAlertInput:(id)sender {
// 准备初始化配置参数
NSString title = @"Email Address";
NSString message = @"Please enter your your email address:";
NSString okButtonTitle = @"OK";
// 初始化
UIAlertController alertDialog = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
// 创建文本框
[alertDialog addTextFieldWithConfigurationHandler:^(UITextField textField){
textFieldplaceholder = @"Your Email";
textFieldsecureTextEntry = NO;
}];
// 创建 *** 作
UIAlertAction okAction = [UIAlertAction actionWithTitle:okButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction action) {
// 读取文本框的值显示出来
UITextField userEmail = alertDialogtextFieldsfirstObject;
selfuserOutputtext = userEmailtext;
}];
// 添加 *** 作(顺序就是呈现的上下顺序)
[alertDialog addAction:okAction];
// 呈现警告视图
[self presentViewController:alertDialog animated:YES completion:nil];
}
在创建 *** 作前先创建文本框,以便后面的按键可以 *** 作文本框内容。创建文本框也只是用了一个简单的方法而已,想创建更多文本框就再使用多次这个方法即可,程序效果如下:
4 提醒图表
与第2个和第3个方法相比,创建提醒图表简直易如反掌。因为和第1个方法相比,只需要改动一个参数就可以,即把创建UIAlertController实例的参数 UIAlertControllerStyleAlert 改为 UIAlertControllerStyleActionSheet ,别的都不用变。
[objc] view plain copy
- (IBAction)doActionSheet:(id)sender {
// 准备初始化配置参数
NSString title = @"Alert Button Selected";
NSString message = @"I need your attention NOW!";
NSString okButtonTitle = @"OK";
NSString neverButtonTitle = @"Never";
NSString laterButtonTitle = @"Maybe Later";
// 初始化
UIAlertController alertDialog = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet];
// 分别3个创建 *** 作
UIAlertAction laterAction = [UIAlertAction actionWithTitle:laterButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction action) {
// 普通按键
selfuserOutputtext = @"Clicked 'Maybe Later'";
}];
UIAlertAction neverAction = [UIAlertAction actionWithTitle:neverButtonTitle style:UIAlertActionStyleDestructive handler:^(UIAlertAction action) {
// 红色按键
selfuserOutputtext = @"Clicked 'Never'";
}];
UIAlertAction okAction = [UIAlertAction actionWithTitle:okButtonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction action) {
// 取消按键
selfuserOutputtext = @"Clicked 'OK'";
}];
// 添加 *** 作(顺序就是呈现的上下顺序)
[alertDialog addAction:laterAction];
[alertDialog addAction:neverAction];
[alertDialog addAction:okAction];
// 呈现警告视图
[self presentViewController:alertDialog animated:YES completion:nil];
}
这个就很简单了,跟第2个方法很像,效果如图:
5 播放系统声音、提醒声音和振动设备
在 iOS 8 中,调用声音的方法发生了小变化,用曾经的方式无法获取系统声音文件的 soundID 。因此,这里直接调用 soundID 值来调用对应的声音,注意振动仍然正常调用kSystemSoundID_Vibrate常量即可:
[objc] view plain copy
- (IBAction)doSound:(id)sender {
// 播放系统声音
AudioServicesPlaySystemSound(1005);
}
- (IBAction)doAlertSound:(id)sender {
// 播放提醒声音
AudioServicesPlayAlertSound(1006);
}
- (IBAction)doVibration:(id)sender {
// 执行震动
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}
这样在 iOS 8 中就可以对用户发出提示了。
从编码到生成可执行的binary文件是有好几个过程的:(默认已完成编码)
1, 预编译(预处理), 也就是替换工作, 先把代码中的宏做替换, 条件编译等会做处理,为编译做作准备;
2,编译,包括了语法的检查,汇编代码等中间代码的生成,代码优化,obj文件(也算是目标代码)的生成,已经是有机器码了;
3库的合成,这个不一定有,不是必须的;
4链接, 连接器会按照一定的规则,比如根据连接脚步,把code组织起来,生成elf文件(elf可能不是一个所有通用的格式),这个时候已经可以执行了,里面的可以执行的机器码;
5,裁剪, 可以把elf文件中的非必需的段 strip,生成一个更精简的elf文件;
6,binary的生成,objcopy命令可以把elf文件转换成binary文件,binary文件烧录到存储器中可以直击运行。
runtime 在iOS中是“运行时”的含义,是一套用c语言写的api,很多人会用但是也仅仅用过最最常用的几个函数,这次,我将详细的带着大家探索下 runtime 的API,这一章就说下 <objc/runtimeh> 这个文件里的 API ,并且我会把不适用于 ARC 和不支持64位的API剔除掉。
首先,我们先看一个简单的函数:
这个函数是通过传入 Class 类型的 cls 来得到 Class 的名字。那我们测试下这个函数:
其中 [Person class] OC中获得 Class 的方法,当然,你也可以用 runtime 里面的 objc_getClass 等函数,后面我也会讲到。
运行结果:
我们可以看到打印出来的结果就是类的名字。
上面既然用到了 [Person class] ,那我们就看下在 runtime 中 [Person class] 的替代函数,都是通过名字来获得 Class
那这三个有什么区别,从结论上讲, objc_getClass 和 objc_lookUpClass 的效果是一致的,在最新的源码里面,这两个方法调用的底层也是一致的,当你要找的类不存在的话,就返回nil,而 objc_getRequiredClass 里你要找的类不存在的话,就会崩溃。下面我们来测试下,我们创建一个 Person 类。
运行结果:
最后也确实崩溃了,所以大家使用 objc_getRequiredClass 这个函数时候要慎重小心。
除了用名字获得类对象以外,还可以用实例对象来获取:
我们测试下:
运行结果:
完全没问题。
Class 不仅可以代表类对象,也可以代表元类对象,下面这个函数就是通过名字获取元类对象。
如果你读过源码的话,你就会清楚元类对象储存的是类方法,类对象储存的是实例方法,在后面讲到Method相关的API的时候,我们在具体讲他们之间的区别。
讲到元类对象,我们还要关注下这个函数,
这个函数是用来判断是否是元类对象。
运行结果:
我们可以看到 objc_getMetaClass 生成才是元类对象, objc_getClass 生成的只是类对象。
那么有没有函数区分类(元类)对象和实例对象呢?当然有:
这个方法只要是类对象或者元类对象都会返回YES:
运行结果:
当然也可以获得父类对象。
我们新建一个继承 Person 的类 Student ,然后我们通过 Student 类来获得 Person 类。
运行结果:
Student 的父类确实是 Person 。
我们知道OC里面可以强转类型,当然, runtime 里面也有相关方法
这个方法的意思是给一个实例对象设置新的类,返回旧的类
运行结果:
我们可以看出开始的时候 student 的类是 Student ,用了 object_setClass 后就是 Person 类了。
runtime 的动态性还可以动态新增类,下面四个函数分别表示为一个类分配内存,注册一个类,复制一个类,销毁一个类
创建一个新类, superclass 是新类所继承的类,如果为 nil , superclass 就默认为根类,也就是 NSObject , extraBytes 是在类和元类对象的末尾为索引ivars分配的字节数。这一般是0, name 是新类的名字。
注册类,如果这个类 objc_allocateClassPair 好了,就必须 objc_registerClassPair 才能使用。
这个方法在系统KVO的底层用过,系统不推荐我们自己用。
objc_disposeClassPair 只能销毁通过 objc_allocateClassPair 创建的类。
我们写个demo来测试这些方法, objc_duplicateClass 官方不建议使用,那么我们就不测试这函数。
运行结果:
我们可以知道如果仅仅只是 objc_allocateClassPair 的话,你是找不到这个类的,必须再 objc_registerClassPair 才可以找到, objc_disposeClassPair 则是把类销毁掉,所以再实际开发中,如果我们不再使用自建类的时候,就要及时销毁,节省内存。
下面两个函数是关于整个工程的类列表的函数:
这个函数是获得所有注册类的列表,我们试用下:
运行结果:
我们看到注册的类有15765个。
objc_getClassList 也是获取注册类的方法
第一个参数 buffer 已分配好内存空间的数组指针, bufferCount 是数组的个数,如果 bufferCount 的数量小于实际的数组数量,那么 buffer 返回的是所有数组集合的任意一个子类。如果 buffer 为NULL,那么 bufferCount 为0。无论那种情况,返回结果都是当前注册类的总数。
运行结果:
返回类实例的大小。
运行结果
一个没有变量或属性的继承于NSObject的类占有8个字节。
还有个方法是:
这是一个创建实例的方法, cls 是要创建的类, extraBytes 是额外的字节内存,用来存储类定义中的实例变量之外的其他实例变量。在源码中 alloc 方法底层就是用的这个函数。那么,我们用这个函数来初始化 Person 类:
运行结果:
确实能够成功创建出来。
最后剩下两个方法:
这两个方法都和 version 有关,这个version在实际中我也没发现用处,可能是在改变类的变量或者方法时给定一个标识
运行结果
下面我们将使用runtime里面最最常用的api,也就是给分类绑定对象,这里,我们先了解下,一个枚举:
objc_AssociationPolicy 是一个枚举,里面的枚举值分别代表要添加的属性的修饰类型。
OBJC_ASSOCIATION_ASSIGN 相当于 weak
OBJC_ASSOCIATION_RETAIN_NONATOMIC 相当于 strong 和 nonatomic
OBJC_ASSOCIATION_COPY_NONATOMIC 相当于 copy 和 nonatomic
OBJC_ASSOCIATION_RETAIN 相当于 strong 和 atomic
OBJC_ASSOCIATION_COPY 相当于 copy 和 atomic
关于分类的runtime函数,主要有下面3个:
含义分别为设置关联对象,获得关联对象,删除关联对象。
我们知道如果在分类的 h 文件设置属性并没有用,调用的时候会发生闪退,这是因为系统并没有自动为属性生成 Set 和 Get 方法,所以,我们用上面三个方法来手动关联对象。
我们创建一个 Person 的分类 Person+Actorh ,在h文件里新建一个新属性 @property(nonatomic, assign)float actingSkill 而不做其他任何处理,这时候, m 文件就会有警告。
这时候就绑定好了。
在 ViewController 里面去使用下这个属性
运行结果:
说明set和get方法都成功了。
那么还有一个 objc_removeAssociatedObjects 方法还没用,这个方法是解除绑定,为了测试这个效果,我们在ViewController里面 touchesBegan 里面去调用这个方法。
运行结果:
之前绑定的结果被移除了。
今天我们这一篇就讲到这, runtime 还有很多其他的用法我们下一篇见。
对了,这个是 demo ,喜欢的可以点个星。
看文红色部 量环境变量供设置影响 GCC 编译程序式利用些变量控制使用合适命令行选项些环境变量设置目录名列表些名字 PATH 环境变量使用格式相同特殊字符 PATH_SEPARATOR (安装编译程序候定义)用目录名间 UNIX 系统隔符冒号 Windows 系统号 C_INCLUDE_PATH 编译C 程序使用该环境变量该环境变量指定或目录名列表查找文件像命令行指定 -isystem 选项首先查找 -isystem 指定所目录 ==> 见 CPATH 、 CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH 该环境变量指定或目录名列表没指定 GCC_EXEC_PREFIX 定位程序编译程序查找程序 ==> 见 LIBRARY_PATH 、 GCC_EXEC_PREFIX -B 命令行选项 CPATH 编译C 、 C++ Objective-C 程序使用该环境变量该环境变量指定或目录名列表查找文件像命令行指定 -l 选项首先查找 -l 指定所目录 ==> 见 C_INCLUDE_PATH 、 CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH CPLUS_INCLUDE_PATH 编译C++ 程序使用该环境变量该环境变量指定或目录名列表查找文件像命令行指定 -isystem 选项首先查找 -isystem 指定所目录 ==> 见 CPATH 、 C_INCLUDE_PATH OBJC_INCLUDE_PATH DEPENDENCIES_OUTPUT 文件名设置该环境变量让预处理程序基于依赖关系 makefile 规则写入文件包括系统文件名字 环境变量设置单名看作文件名字依赖关系规则名字自源文件名字定义两名字则第二名字用作依赖关系规则目标名 设置该环境变量结使用命令行选项 -MM 、 -MF -MT 组合 ==> 见 SUNPRO_DEPENDENCIES GCC_EXEC_PREFIX 定义该环境变量作编译程序执行所程序名字前缀例变量设置 testver 查找 as 汇编器首先名字 testveras 查找没找编译程序继续根据普通名进行查找前缀名使用斜线指路径名 GCC_EXEC_PREFIX 默认设置 prefix /lib/gcc-lib/ prefix 安装编译程序 configure 脚本指定名字该前缀用于定位标准连接程序文件包含进作执行程序部 使用 -B 命令行选项重写该设置 ==> 见 COMPILER_PATH LANG 该环境变量用于指编译程序使用字符集创建宽字符文字、串文字注释 定义LANG C-JIS 指预处理程序字节字符按照 JIS (语工业标准)字符进行解释 C-SJIS 用指 Shift -JIS 字符 C-EUCJP 指文 EUC 没定义 LANG 或定义识别函数 mblen() 用确定字符宽度 mbtowc() 用字节序列转换宽字符 LC_ALL 设置该环境变量值重写 LC_MESSAGES LC_CTYPE 所设置 LC_CTYPE 该环境变量指引用串定义字节字符字符类主要用于确定字符串字符边界字符编码需要用引号或转义符错误解释字符串结尾或特殊字 符串 Australian English 设置 en_AU ; Mexican Spanish 设置 es_MX 没设置该变量默认 LANG 变量值或没设置 LANG 使用 C 英语行见 LC_ALL LC_MESSAGES 该环境变量指编译程序使用何种语言发诊断消息 Australian English 设置 en_AU ; MexicanSpanish 设置 es_MX 变量没设置使用 LANG 变量默认值或没设置 LANG 使用 C 英语行见 LC_ALL LD_LIBRARY_PATH 该环境变量影响编译程序程序运行候影响变量指定目录列表程序查找该列表定位共享库未编译程序目录找共享库候执行程序必须设置该变量
Property是属性y,Ivar是成员变量
其实分类中是可以为一个类添加属性的,但是一定做不到添加成员变量,不要混淆了成员变量和属性的概念
在一个分类中添加了一个属性,Xcode不会自动的为其生成一个下划线开头的成员变量及set和get方法,如果你没有手动的实现这两个方法,直接在外面通过点语法调用这个属性,肯定就直接挂了,Unrecognised selector send to instance,因为他压根就没有这两个方法,所以当你真的在分类中声明了一个属性的时候,就要手动的去实现这个属性的set和get方法,这个时候就要用到运行时机制了,关联上去这个属性的存取过程。
那么为什么不能给分类添加成员变量呢
成员变量是一个类的东西,分类本身就不是一个类,分类本来就是OC里面通过运行时动态的为一个类添加的一些方法和属性等,不是一个真正的类,你怎么给他添加成员变量呢?
分类里面不能添加Ivar是因为分类本身并不是一个真正的类,它并没有自己的ISA。类最开始生成了很多基本属性,比如IvarList,MethodList,分类只会将自己的method attach到主类,并不会影响到主类的IvarList。这就是为什么分类里面不能增加成员变量的原因。
为什么不能添加成员变量呢?
Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。它的定义如下:
typedef struct objc_class Class;
objc_class结构体的定义如下:
structobjc_class{Class isa OBJC_ISA_AVAILABILITY;#if!__OBJC2__Class super_class OBJC2_UNAVAILABLE;// 父类constcharname OBJC2_UNAVAILABLE;// 类名longversion OBJC2_UNAVAILABLE;// 类的版本信息,默认为0longinfo OBJC2_UNAVAILABLE;// 类信息,供运行期使用的一些位标识longinstance_size OBJC2_UNAVAILABLE;// 该类的实例变量大小structobjc_ivar_listivarsOBJC2_UNAVAILABLE;// 该类的成员变量链表structobjc_method_listmethodListsOBJC2_UNAVAILABLE;// 方法定义的链表structobjc_cachecacheOBJC2_UNAVAILABLE;// 方法缓存structobjc_protocol_listprotocolsOBJC2_UNAVAILABLE;// 协议链表#endif} OBJC2_UNAVAILABLE;
在上面的objc_class结构体中,ivars是objc_ivar_list(成员变量列表)指针;methodLists是指向objc_method_list指针的指针。在Runtime中,objc_class结构体大小是固定的,不可能往这个结构体中添加数据,只能修改。所以ivars指向的是一个固定区域,只能修改成员变量值,不能增加成员变量个数。methodList是一个二维数组,所以可以修改methodLists的值来增加成员方法,虽没办法扩展methodLists指向的内存区域,却可以改变这个内存区域的值(存储的是指针)。因此,可以动态添加方法,不能添加成员变量。
在Objective-C提供的runtime函数中,确实有一个class_addIvar()函数用于给类添加成员变量,但是文档中特别说明:
This function may only be called after objc_allocateClassPair and before objc_registerClassPair Adding an instance variable to an existing class is not supported
意思是说,这个函数只能在“ 构建一个类的过程中 ”调用。一旦完成类定义,就不能再添加成员变量了。经过编译的类在程序启动后就runtime加载,没有机会调用addIvar。程序在运行时动态构建的类需要在调用objc_allocateClassPair之后,objc_registerClassPair之前才可以被使用,同样没有机会再添加成员变量。
Category不能添加成员变量(instance variables),那到底能不能添加属性(property)呢?
这个我们要从Category的结构体开始分析:
typedefstructcategory_t{constcharname;//类的名字classref_tcls;//类structmethod_list_tinstanceMethods;//category中所有给类添加的实例方法的列表structmethod_list_tclassMethods;//category中所有添加的类方法的列表structprotocol_list_tprotocols;//category实现的所有协议的列表structproperty_list_tinstanceProperties;//category中添加的所有属性}category_t;
从Category的定义也可以看出Category的可为(可以添加实例方法,类方法,甚至可以实现协议,添加属性)和不可为(无法添加实例变量)。
那我们为什么经常听说说类别不能添加属性呢?实际上,Category实际上允许添加属性的,同样可以使用@property,但是不会生成_变量(带下划线的成员变量),也不会生成添加属性的getter和setter方法,所以,尽管添加了属性,也无法使用点语法调用getter和setter方法。那我们想要实现我们平时的属性所具有的功能应该怎么样做呢?
其实我们可以使用runtime去做,使用runtime去实现Category为已有的类添加新的属性并生成getter和setter方法。不要忘记了Objective-C是动态语言。方法是通过runtimeh中objc_getAssociatedObject / objc_setAssociatedObject来访问和生成关联对象。这两个方法可以让一个对象和另一个对象关联,就是说一个对象可以保持对另一个对象的引用,并获取那个对象。
//NSObject+IndieBandNameh@interfaceNSObject(IndieBandName)@property(nonatomic,strong)NSStringindieBandName;@end
上面是头文件声明,下面的实现的m文件:
// NSObject+IndieBandNamem #import"NSObject+Extensionh"#importstaticconstvoidIndieBandNameKey = &IndieBandNameKey;@implementationNSObject(IndieBandName)@dynamicindieBandName;- (NSString)indieBandName {returnobjc_getAssociatedObject(self, IndieBandNameKey);}- (void)setIndieBandName:(NSString)indieBandName { objc_setAssociatedObject(self, IndieBandNameKey, indieBandName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}@end
通过runtime的两种方法就可以为类别添加一个实例变量了。
通过类名来获取一个类对象,传入 const char 返回对应的类对象。
示例:
传入一个对象,获取该对象 isa指针 指向的 对象 。
示例:
实例对象、类对象调用 class 方法都返回类对象
示例:
1 OC的数组成员是任意的对象指针 与C中的链表结构类似(以nil结尾) 一切的数组 *** 作不能越界
OC的数组分为不可变数组 NSArray 可变数组 NSMutableArray
[cpp] view plain copy
<pre name="code" class="objc">字符串数组初始化写法,相较于c++,比较奇怪因为他是作为一个对象在实现对象实例初始化,整个格式都是这样
[cpp] view plain copy
<pre name="code" class="objc">NSArray array = [[NSArray alloc]initWithObjects:@"one",@"two",@"three", nil];
[cpp] view plain copy
<pre name="code" class="objc">NSLog(@"%@",[array objectAtIndex:0]);//通过下标获取数组成员(下标从0开始
[cpp] view plain copy
<pre name="code" class="objc">NSLog(@"%ld",[array count]);//获取数组有效成员个数 (不包括nil)
[cpp] view plain copy
<pre name="code" class="objc">for (i = 0; i < [array count]; i++) {//遍历数组(C方法)
[cpp] view plain copy
<pre name="code" class="objc"> NSLog(@"%@",[array objectAtIndex:i])
[cpp] view plain copy
<pre name="code" class="objc">}
[cpp] view plain copy
<pre name="code" class="objc">NSLog(@"%@",array);//(OC)查看数组内容(先给array发送description消息,然后给每个成员都发送一个description消息
[cpp] view plain copy
<pre name="code" class="objc">NSArray array1 = [[NSArray alloc]initWithArray:array];//创建数组对象 相当于拷贝
[cpp] view plain copy
<pre name="code" class="objc">NSArray arry2 = [NSArray arrayWithArray:array];//创建数组对象 相当于拷贝
[cpp] view plain copy
<pre name="code" class="objc">NSEnumerator enumer = [array objectEnumerator];//正序枚举器
[cpp] view plain copy
<pre name="code" class="objc">//创建一个枚举器 把数组的每个元素的地址一次赋给枚举器,然后建立起某种关联 (枚举器只能用来读数组成员)
[cpp] view plain copy
<pre name="code" class="objc">//枚举时 会和数组创建某种关联(修改监视器/迭代器) 限制枚举的同时不能修改元素 只能读不能写
[cpp] view plain copy
<pre name="code" class="objc">id obj;
[cpp] view plain copy
<pre name="code" class="objc">//第一次循环把数组的第一个元素赋给obj 第二次循环把第二个数组元素赋给obj
[cpp] view plain copy
<pre name="code" class="objc">while (obj = [enumer nextObject]) { //遍历数组
[cpp] view plain copy
<pre name="code" class="objc"> NSLog(@"%@",obj);
<pre name="code" class="objc">}
[cpp] view plain copy
<pre name="code" class="objc">//快速枚举 第一次循环把array的第一个元素赋给ob 第二次循环把array的第二个元素赋给ob 直到nil(只能读不能改)
[cpp] view plain copy
<pre name="code" class="objc">for(id ob in array){
[cpp] view plain copy
<pre name="code" class="objc"> NSLog(@"%@",ob);
[cpp] view plain copy
<pre name="code" class="objc">}
<pre name="code" class="objc">//逆序输出数组(创建逆序枚举器 第一次循环把最后一个元素赋给obj )
<pre name="code" class="objc">NSEnumerator enumer1 = [array reverseObjectEnumerator];
[cpp] view plain copy
<pre name="code" class="objc">while (obj = [enumer1 nextObject]) {
[cpp] view plain copy
<pre name="code" class="objc"> NSLog(@"%@",obj);
[cpp] view plain copy
<pre name="code" class="objc">}
[cpp] view plain copy
<pre name="code" class="objc">if ([obj isKindOfClass:[Dog class]]) //获取类的类型 判是否是指定类的对象
[cpp] view plain copy
<pre name="code" class="objc"> if ([obj isMemberOfClass:[Dog class]]) {
[cpp] view plain copy
<pre name="code" class="objc"> }
2 不可变数组
[objc] view plain copy
-------查找
[objc] view plain copy
<span style="font-family: Arial, Helvetica, sans-serif;">NSArray array = [[NSArray alloc]initWithObjects:@"one",@"two",@"three",@"one", nil nil];</span>
NSUInteger index = [array indexOfObject:@"one123"];//返回第一个找到的数组成员对应的下标 找不到返回NSNotFound
[objc] view plain copy
index = [array indexOfObject:@"one" inRange:NSMakeRange(1, 3)];//在指定范围内查找
[objc] view plain copy
if (index != NSNotFound) {
NSLog(@"%ld",index);
}
----抽取 组成新的数组
[objc] view plain copy
NSArray array1 = [array objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 3)]];
《数字集合》
[objc] view plain copy
NSIndexSet这是个数字集合类
[objc] view plain copy
[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 3)]产生一个数字集合
3 可变数组
[objc] view plain copy
NSMutableArray array = [[NSMutableArray alloc]initWithObjects:@"one",@"two",@"three",@"four", nil nil];
[array addObject:@"five"];//在数组尾部插入元素
[array insertObject:@"six" atIndex:5];//在数组指定下标位置插入元素(不能越界,最大值为length)
[array removeObject:@"six"];//删除指定元素(数组中出现的所有位置都将被删除)
[objc] view plain copy
[array removeObject:@"two" inRange:NSMakeRange(0, 3)];//从指定下标位置开始的指定长度内删除指定元素
[objc] view plain copy
[array removeLastObject];//删除最后一个元素
[objc] view plain copy
[array removeAllObjects];//删除所有元素<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
[array replaceObjectAtIndex:3 withObject:@"ios"];//将指定下标位置元素替换为指定的元素
[array exchangeObjectAtIndex:0 withObjectAtIndex:3];//将指定下标的两个元素进行交换
4 字符串分割与拼接
[objc] view plain copy
//@"" 空的字符串对象
-------分割
NSString ptr = @"I am a man";
[objc] view plain copy
NSArray array = [ptr componentsSeparatedByString:@" "];//将字符串整体作为分割条件 返回值为NSArray不可变数组
[objc] view plain copy
NSMutableArray array1 = [NSMutableArray arrayWithArray:array];//若修改,则将NSArray转化为NSMutableArray
[objc] view plain copy
NSArray array2 = [ptr componentsSeparatedByCharactersInSet:[NSCharacterSet
[objc] view plain copy
characterSetWithCharactersInString:@", "]];//以字符串中的字符作为分割条件进行分割
《字符集合》
NSCharacterSet 这是个字符集合类
[NSCharacterSet characterSetWithCharactersInString:@", "]//把字符串转化为字符集合
-------拼接
NSString str = [array componentsJoinedByString:@" "];
若分割条件出现在开头或者结尾,则会出现空串@"",如果不需要,则需要转化成NSMutableString对空串进行处理
func1: [array1 removeObject:@""]; //找到空串直接删除
func2: for(id obj in array1){
if([obj length] == 0) //空串的长度为0
if([obj isEqualToString:@""]) //与空串进行比较(字符串是不能进行==比较的,要使用函数)
}
5 获取绝对路径中文件名(测试通过)
lastPathComponent
6 另一种获取绝对路径中文件名的方法,测试未通过,但思路有保留价值
NSArray splitArr=[filepath componentsSeparatedByString:@"//"];//注意转义字符
NSString fileName = [splitArr lastObject];
以上就是关于ios怎么获取uialertcontroller输入框的值全部的内容,包括:ios怎么获取uialertcontroller输入框的值、C语言编译到机器码的过程求详细解说,不胜感激、iOS之runtime详解api(一)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)