iOS开发总结(一)——刚接触 iOS 开发的那日子
环境:Xcode4.2 SDK:iOS 5
1、卸载和安装Xcode
公司发的macbook pro本来有安装Xcode4.2,不小心在/Develop/Application中的Xcode扔垃圾桶了。按照网上的教程在终端(Terminal)中输入如下命令卸载:
sudo /Developer/Library/uninstall-devtools --mode=all
然后删除Develop文件夹。
使用Xcode的安装包进行安装,遇到错误。经过查找,修改了系统时间,改为2012/01/01,即可正常安装。
ps:如果还不可以,可尝试关闭iTune和iTune Helper。后者在Activity Monitor中可以看到,并进行强制结束。
2、学习Objective-C
学习Objective-C。(参考《Objective-C 2.0 Mac 和 iOS开发实践指南》(美)Robert Clair 著;李强等译。北京-机械工业出版社 2011.1)
Objective-C是C的一个超集。C语言的基础再加上面向对象的思想,和一些Objective-C的语法(协议、消息等)。由于我之前是学习C++的,所以C和面向对象方面基本没有问题(除了C需要再复习一下,毕竟和C++的一些语法和使用习惯不一致)。而Objective-C中对象的声明和Java的接口有点相似,当然还是有很大的不同的。刚好我也学过几天Java,可以对应上。而消息其实是函数调用。到最后消息还是一个函数指针的调用。之前我使用过Qt库(一个开源的C++跨平台GUI库),里面的信号和槽机制中的思想有点类似消息。而其中的精髓我也不太懂,不过感觉有点类似。综上,对于Objective-C,出了需要熟悉一些语法和一些高级特性外,基本没什么难度。不过文档中的例子感觉比较少(或者我还没有发现)。
定义类
@interface 和 @end 表示接口部分的开始和结束。Objective-C中以@字符开始的单词,是编译器指令,用来指示编译器,而不是可执行的代码。
实例方法以 - 开头,类方法以 + 开头(所有方法都是共有的。减号表示实例,加号表示静态方法)。
按照惯例,Objective-C方法名以一个小写字符开头。方法名的剩下部分则遵循CamelCased命名法, 即名称中的齐豫的每个单词,都以一个大写字符开头,并且,不会用一个下划线字符 _ 将单词隔开。
方法的实现放在 @implementation 和 @end 之间。
示例:
Accumulator.h
@interface Accumulator : NSObject
{
int total;
}
- (void) addToTotal: (int) amout;
- (int) total;
- (void) zeroTotal;
@end
Accumulator.m
#import "Accumulator.h"
@implementation Accumulator
- (void) addToTotal:(int)amout
{
total += amout;
}
- (int) total
{
returntotal;
}
- (void) zeroTotal
{
total = 0;
}
@end
Objective-C简单概览。
1、运行时
运行时是C函数的一个动态链接库。负责建立和运行Objective-C的消息系统。
2、名称
对象的名称区分大小写。一些命名规则如下:
方法可以与实例变量具有相同的名称(对于返回一个实例变量的值的方法来说,这很常见)。
类的实例方法可以拥有与同一个类的类方法相同的名称。
Apple 将名称以下划线 _ 字符开始的方法,视为保留供 Apple 内部使用的方法。
3、消息表达式
[receiver message]
4、编译器指令
以@字符开头的单词是编译器指令。
5、直接量字符串
直接量字符串是保存字符串文本的常量。Objective-C使用NSString的常量实例而不是普通的C字符串。
“The Big Apple" // Literal C string
@“The Big Apple" // Literal NSString
注: 严格地讲, @“The Big Apple" 是一条编译器指令,它告诉编译器创建一个NSString直接量,其文本为“The Big Apple"。
6、Objective-C关键字
id、nil、BOOL、SEL、IMP、Class。
7、Cocoa数字类型(该部分不是Objective-C语言的一部分。它们都定义于Cocoa框架中,但是,会经常出现)
NSInteger,替代了Cocoa框架中大多数 int 的出现。在32位环境中定义为 int ,在64位环境中定义为 long (64位整数)。
NSUInteger,NSInteger的无符号形式。
CGFloat,替代了 float 。float(32),double(64)。Foundation 框架提供了一个定义的常量,CGFLOAT_IS_DOUBLE ,
如果需要通过编程知道 CGFloat 在当前的环境中是一个 float 还是一个 double ,使用下面的语句。
if ( CGFLOAT_IS_DOUBLE)
NSLog( @"Double !");
else
NSLog( @"Float !");
NSLog,是Foundation框架中定义的一个用于字符输出的函数。类似于 printf 函数,但是有如下区别:
写入控制台日志,也写入一个终端窗口。在OS X上,可以使用Console应用程序来查看控制台日志。
格式字符串是一个NSString直接量(如NSLog( @"Double !")),而不是一个C字符串直接量。
在打印后自动换行,不需要在格式字符串末尾添加一个额外的 \n 。
使用一个额外的转换修饰符, %@ ,它接受一个Objective-C对象作为参数。在转换中,NSLog调用参数对象的 description 方法。
该方法返回一个NSString,用以描述对象。返回的NSString替代了输出中的 %@。当创建自己的类时,可以覆盖 description 方法为自己的类提供自制的描述。
注: 如果使用带有%@ 描述符的格式字符串,但是,忘记了提供一个对象的对象参数,那么NSLog 将尝试向位于对象参数所应该防止的地址的字节发送一条description消息。这可能会导致程序崩溃。
方法、消息表达式和消息系统机制。
类的隐藏变量 self,和 C++ 的this指针类似。
没有参数的方法: - (NSColor*) fillColor; 此时,方法名称为 fillColor。
一个参数的方法: - (void) setFillColor: (NSColor*) newFillColor; 此时,方法名称为 setFillColor: (冒号是方法名称的一部分)。
多个参数的方法: - (void) setOutlineColor: (NSColor*) outlineColor
fillColor: (NSColor*) fillColor; 此时,方法名称为setOutlineColor:fillColor: (注意冒号)。
在Xcode中编译运行C++
7.9晚上,由于刚好想写一个简单的C++程序,可是不知道在Xcode(4.2)中如何编译运行。通过搜索网上资料(搜索了几篇,不正确)再结合自己的测试,方法如下。
直接创建Project,Max OS X->Application->Command Line Tool。把 main.m 后缀 .m 改为 .mm或者.cpp 即可正确编译运行程序。前者为C++ 和 Objective-C混编时的后缀,后者为C++源码文件的后缀
3、NSLog() 相关问题
1、
NSString* tempMessage = @"Hello World!";
NSLog(tempMessage);
上述两行代码可正常运行,而第二行代码出现警告。由于NSLog函数的原型为void NSLogv(NSString *format, va_list args)和void NSLog(NSString *format, …)。
所以第一个参数应该为说明格式化的一个字符串,故而不能单单出现一个参数。修改如下:
NSLog(@"%@", tempMessage);
无警告,可运行。
2、在发布时,将 NSLog 的控制台输出
#define NSLog(…)
#ifdef __OPTIMIZE__
#define NSLog(...)
#endif
__OPTIMIZE__通常是在发布版本中定义的。
看到网上有几种方案,一种是定义一个自己的 log 函数,不过这个可能会比较麻烦,需要多记一个。
还有就是使用 TARGET_IPHONE_SIMULATOR 宏定义
#ifndef TARGET_IPHONE_SIMULATOR
# define NSLog(...) NSLog(__VA_ARGS__)
#else
# define NSLog(...) {}
#endif
但是如果使用该宏定义的话,则使用真机进行调试也不可看到 log 输出了。
所以还是使用 __OPTIMIZE__最好。
ps:
TARGET_IPHONE_SIMULATOR ,模拟器宏定义,在模拟器上运行。可用于判断是真机或者模拟器
OPTIMIZE 是优化的意思,估计在发布时会进行优化。
4、关于 @property 和 @synthesize
示例如下:
.h 中
@property (nonatomic, retain) NSString* secretString;
.m 中
@synthesize secretString;
上面的代码,编译器会自动生成读写方法。如下:
- (NSString*) secretString
{
return secretString;
}
- (void) setSecretString : (NSString*) newValue
{
if (newValue != secretString)
{
[secretString release];
secretString = [newValue retain];
}
}
使用 retain 关键字,生成的写入方法会检查新值,确保与旧值不是同一个对象,然后释放旧值,持有新值(赋值)。
若使用assign关键字,则不检查,直接赋值,如 secretString = newValue。这样写从技术上是可行的,但是可能会出现问题。对于基本类型比如 boolean 和 int,是不能使用引用计数的。
ps:在 Xcode4.5(具体不清楚,不过现在都用4.5以上了估计)之后,可不写 @synthesize,编译器会自动处理,编译器特性,不是语言特性。
5、关于内存管理的简述
5.1 用 alloc、new、copy 或者 mutableCopy (名称包含了copy的)创建的对象,必须用 release 释放。
5.2 对于其他任何对象,都可以认为引用计数为1,同时处于自动回收池中。
想把对象放到自动回收池中,只要向它发送 autorelease消息即可:[aString autorelease];
5.3 使用ARC (auto reference count)
6、移除(删除)iphone模拟器上的应用(当初没玩过 iPhone ,呵呵,菜鸟ing)
在图标上长按,每个图标会显示虚线闪动外框并有删除图标
7、调试时无法显示变量内容,使用 printf 代替(并没有找到根本的解决方法,只是一个替代方法)
在调试时,如果鼠标放在一个变量上没有显示信息,或者在控制台使用gdb的po、print等命令无法打印该变量的内容、而且NSLog也不能使用的时候,那就用 printf 吧。还是最原始的C函数管用啊!不知道 C++ 的 cout能不能用。如果要打印NSString 变量的内容,记得调用UTF8String 这个方法。示例:
NSString* tmpStr = @“It's a temp string";
printf("%s", [tmpStr UTF8String]);
过了一阵子就自动好了,不明所以中。
8、添加 framework
9、关于"_ABAddressBookCreate", referenced from 错误的解决方法(添加 framework 操作的低级错误)
build项目会提示出错:"_ABAddressBookCreate", referenced from……所有使用ABAddressBook相关函数都会出错。而且在源代码中显示绿色。一般自定义类或函数才显示绿色,从这个也可以看出问题可能和本地的设置(或相关的方面)有关系。
之后另写了一个demo,按照正常的方式添加AddressBook.framework(见第8点),可以正常运行。对比两个项目的设置,终于发现了问题。
在targets->build settings,search paths条目下的framework search paths设置了项目路径,所以搜索AddressBook.framework出错了(framework search paths设置出错,应该为空)。可能之前不知道在哪里添加framework,从目录直接添加的,所以出现这个问题了。
该解决方法应该能运用在:添加framework之后还出错的情况。
10、UITableView和UITableViewCell
UITableView和UITableViewCell的一些简单用法
11、UIButton 设置相应状态下的图片,并对图片进行边界设置(可起到缩放的效果)
选中按钮时改变图标。
setImage:forState:(不同的state对应不同的图片)
imageEdgeInsets方法设置按钮中的image的边界(sdk:The inset or outset margins for the edges of the button image drawing rectangle.),可使图片按照想要的size出现。