推荐:XCode 4视频教程

上一个项目做的差不多了,所以这几天尝试了下XCode 4,发现4与3的区别蛮大的,快捷键也改变了不少,一些功能也不知为何被精简了,比如User Script(应该是被Code Snippet代替了,不过感觉没有Script强大). 看文档实在太麻烦,上网找了找相关资料,发现之前的Become Productive in XCode系列又专门为XCode 4做了10个视频,而且这回是免费的,果断下载过来分享,毕竟看视频要比看文档直观多了。

这里还有个快捷键的PDF

XCode 4的这几个视频虽然感觉不如3的那么经典,但是作为XCode 4的快速入门还是相当有价值的。如果上面那些由于某些原因无法下载,我这里还提供一个115的下载地址,Have Fun。

PS:这篇介绍XCode 4之前的文章都是以XCode 3为基础的,要查看XCode 3的有关文章请通过标签或搜索查询.

–以上–

NSLog对程序性能的影响

NSLog,既可以像printf那样方便地格式化输出,同时还能输出时间以及进程ID等信息,可谓调试利器.但是其实NSLog对程序性能也有不小的影响,在执行次数比较少的情况下可能看不出来什么,当短时间大量执行的时候就会对程序执行效率产生可观的影响.

我遇到的一种情况就是我在一个UIScrollView子类的layoutSubviews方法中输出了很多次log,而这个layoutSubviews本身又有相对繁重的工作要做,由于每次拖动这个UIScrollView都要调用很多次layoutSubviews,因此程序实际运行起来拖动体验就非常差,卡顿现象严重,多次测试发现注释掉所有的NSLog后拖动就变得正常了.

综上,当你疑惑是什么导致了你的程序运行效率很差的时候不妨注释掉那些NSLog试试,你的问题也许就迎刃而解了.

–以上–

[下载]XCode技巧视频教程

这个视频教程之前在这篇文章里提到过,总体来讲是个非常不错的教程,从基本的快捷键到各种TextMarco,自定义脚本等统统介绍了一番,话说"工欲善其事,必先利其器",这个视频教程算是"利其器"必备.

视频以XCode3为基础,XCode4我还没装,某些地方会有挺大区别,这些地方自己查查就好了,等我安装XCode4后会出一个简单的教程介绍一下有区别的内容(不过短期内不会了,所以不要指望我)

支持原作者请通过这篇文章的相应连接寻找.

原版已经不能从官网下载到了, 放出个下载地址

 

关于lvalue required as left operand of assignment

这种错误发生的其中一种情况:

UIView *aView;
aView.frame.size = …….;

第二行会报错,提示lvalue required as left operand of assignment

这里有关于这个错误的解释:

点操作符有两种用法:

1.调用成员变量的getter setter

2.访问结构体

当在等号左边时这两种不能混用,右边可以,所以还是要用这种方法来实现:

aView.frame = CGRectMake(…..)

这只是lvalue required as left operand of assignment错误出现的一种情况,估计其他的也可以类比解决

–以上–

关于initWithCoder导致的内存泄露

initWithCoder一般是通过[NSUnarchiver unarchiveObjectWithData:NSData]调用的, 虽然我们可能感觉代码写得没有什么问题, 但用Performance Tool检测还会有leak. 如果你确定自己的代码没有任何问题, 那么就可以无视Performance Tool的检测. 之所以会检测到内存泄露, 一个可能的原因就是unarchiveObjectWithData:返回的是一个autorelease对象, 而在Performance Tool检测时, autoreleasePool还没有释放, 因此我们可以尝试直接在unarchiveObjectWithData:这个方法附近范围新建一个autoreleasePool然后release它(参考main.m中autoreleasePool的创建和release), 如果Performance Tool不再提示内存泄露, 那么就证明的确没有内存泄露了.

可以参考这里的讨论

–以上–

Objective-C: delegate的那点事儿

Delegate算是Objective-C的一大特性, 关于Delegate的基础就不多介绍了, 有兴趣的请参看文档.

这里仅对Delegate使用中的一些问题做点讨论

我们用Delegate很多情况下是基于多线程的,比如我们有一个ViewController在这个Controller里面进行了一个下载图片的操作,下载成功后需要通过protocol来现实下载成功, 但是当ViewController已经被release,而下载工作才结束, 那么下载工作的[delegate didFinishDownload] (暂且就这么命名吧) 就会产生一个异常,因为你给一个deallocated的对象发送了一个消息.

那么,如何解决这个问题呢,首先我们可能想到用if (delegate == nil) 来判断delegate是否存在,但其实这是不行的,因为已经dealloc的对象并不是nil.要知道Objective-C中给nil发送消息是可以的,所以如果这种方法可行,其实我们就根本不需要if这句,[delegate didFinishDownload] 给nil发送了一个消息也不会出现异常,因此这种方法只是重复了上面的错误.

还有一个叫[delegate respondsToSelector:SEL]来判断delegate是否响应一个Selector, 根据上一段的描述,我们也可以判断出这个也是不行的.这里额外提一点关于respondsToSelector的东西,要使用这个方法,必须有@protocol MyProtocol <NSObject>,因为respondsToSelector是NSObject的一个protocol方法.

既然要防止delegate被release,那么retain这个delegate是否可行呢?这么做虽然避免错误的发生,但是也产生了另一个问题,这就关系到Objective-C内存管理中的Retain Circle, 即:有A,B两个Object, A中有一个B的实例变量,B中又有一个A的实例变量,要release A就必须releaseA中的B,而要release B有必须release B中的A,这样就产生了一个Retain Circle,A B都不能被dealloc.解决Retain Circle的方法就是使用弱引用(weak reference),弱引用没有被引用的那个Object的所有权,也就不需要release它,从而解决了Retain Circle问题.为了防止Retain Circle的发生, delegate通常都是弱引用的, 因此我们一般不应该retain一个delegate.但是似乎有一个例外:NSURLConnection, 网上对其的讨论结果是:NSURLConnection会retain它的delegate,详细可以参考StackOverflow上的这个问题

似乎没有简单可行的方法来解决这个问题(至少在本文发表时我还没有找到),那么我们只能在通过程序结构的设计来解决这一问题了,对应不同的程序自然也就有不同的解决方法,我想到的一种就是在这个ViewConrtoller被release的时候,把下载方法中的delegate设置成nil即可(目前测试可行, 如有错误还请指正).

更新几种解决方法:

–以上–

UITableViewCell的selecte与deselect

首先要从一个我遇到的问题谈起,一个基于NavigationBar的App,开始时我有一个UITableViewController,其中每个UITableViewCell点击后都会push另一个ViewController,每次点击Cell的时候,Cell都会被选中,当从push的ViewController返回的时候选中的Cell便会自动取消选中(有动画效果)。后来由于某些原因我把这个UITableViewController改成了UIViewController,之后就产生了一个问题:每次返回到TableView的时候,之前选中的Cell不能自动取消选中,经过查找得知:

UITableViewController有一个clearsSelectionOnViewWillAppear的property,

而当把UITableViewController修改成UIViewController后,这个属性自然就不存在了,因此我们必须手动添加取消选中的功能,方法很简单,在viewWillAppear方法中加入:

[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];

即可,估计UITableViewController也是用类似的方法来实现取消选中的功能的。

–以上–

XCode SVN 设置指南

经初步测试,使用本文的方法,可以解决文件丢失,commit错误(Error: 155005  Working copy not locked..等)等问题

  • 修改svn配置文件
svn的配置文件在~/.subversions/config
修改方法:
1.找到 global-ignores 一行,去掉注释用的“#”,编辑(添加)成 global-ignores = build *~.nib *.so *.pbxuser *.mode *.perspective*
2.找到 enable-auto-props = yes 把注释去掉(这步似乎可以忽略)
3. 在[auto-props] Section添加以下内容
     *.mode* = svn:mime-type=text/X-xcode
     *.pbxuser = svn:mime-type=text/X-xcode
     *.perspective* = svn:mime-type=text/X-xcode
     *.pbxproj = svn:mime-type=text/X-xcode
 
关于修改配置文件的更多讨论在这里
 
  • SCM Config
XCode 菜单中 SCM >> Configure Repositories
 
按 “+” 添加一项
     Name:任意
     URL:svn://[email protected]/opt/ibmtc/SUBPATH 然后按tab切换 下面那几个除了Password都自动填好了
     Scheme: svn
     Host:svn.footoo.org
     Path:/opt/ibmtc/SUBPATH
     User: USERNAME
     Password: PASSWD
下面有个指示灯,如果显示绿色并有Authenticated字样则表示设置成功
  • 添加项目
1. 如果不是新建的项目 直接到第二步 SCM >> Repositories 选择好对应目录 点Import选择想要进行版本控制的项目(最好是“干净”的项目 即没有.svn文件夹 否则可能有一些错误)
2. 在刚才的窗口选择刚添加的项目 Check out,相当于用svn对项目进行初始化,加入一些控制信息。这一步很重要,缺失了将不能进行版本控制
3. 打开Check out下来的项目 打开项目属性窗口 >> General >> Config Roots & SCM…  下拉按钮选择Subversion 下面的table中的Repository选择你之前在Configure Repositories中添加的那个,一般都会有Recommended字样
 此时在菜单 SCM中就多出了很多项目
在左边的项目树中,邮件点击表头,选择SCM可以多出一栏现实项目修改信息
文件的标示状态简介如下: 

Cocoa中的weak reference

以下所有内容翻译自官方文档,如有不当之处还请各位指正。

Weak Reference to Objects(弱引用)

————————————————————————————————————

retain 一个 object 创建一个 “Strong” reference,一个object在直到它所有的strong reference都release了之后才能dealloc,因此object的生命周期是受它的Strong reference的所有者控制的。某些情况下,这种行为不是我们所期待的,你也许想有一个不会阻止一个object dealloc的reference,这种情况下,你就拥有一个“Weak” reference,weak reference是通过存储一个不retain相应的object的指针所创建的。

 
weak reference在会有循环reference要创建时是必要的。比如,如果Object A和 B之间互相Communicate,它们各自需要一个对方的reference。如果它们各自retain了对方,那么直到它们之间的Connection切断之前它们之中任何一个都不会dealloc,但是它们之间的Connection要等待它们其中任意一个dealloc了之后才能切断,这就产生了一个矛盾。要解决这个问题,其中一个object作为一个次级(subordinate)角色并且拥有对方的一个weak reference。一个具体的例子,在一个view继承体系中,一个parent view拥有并因此retain他的childe views,但是一个child view不拥有它的parent;而又必须知道它的parent是谁,所以就有一个指向它的parent的weak reference。
 
Cocoa中另一些weak reference的例子包括但不局限于这些:table data sources,outline view items,notification observers,各种targets和delegates。(比如一个NSTableView不会retain它的data source,一个NSApplication不会retain它的delegate)
 
当你需要向一个你只拥有weak reference的object发送消息时,就要小心,那个object是不是已经dealloc了,如这这样会使你的程序Crash。
后面又是一些例子(delegate 和notification),不翻译了。

动态调整UITableViewCell高度的实现方法

有时我们需要动态调整UITableViewCell的高度,根据内容的不同设置不同的高度,以前看到一种实现方法,写得有点麻烦,具体地址找不到了,这里有个更好的(至少我认为),分享一下部分代码。

2012.03.11更新:一年后回来审视儿时的代码,发现heightForRowAtIndexPath那个实现方法确实不太好,会dequeue掉一个可以reuse的cell导致经常都要新创建cell,会导致效率方面的问题,最好用NSString的sizeWithFont:forWidth:lineBreakMode:这一系列的方法计算label的高度。


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
		UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
		label.tag = 1;
		label.lineBreakMode = UILineBreakModeWordWrap;
		label.highlightedTextColor = [UIColor whiteColor];
		label.numberOfLines = 0;
		label.opaque = NO; // 选中Opaque表示视图后面的任何内容都不应该绘制
		label.backgroundColor = [UIColor clearColor];
		[cell.contentView addSubview:label];
		[label release];
    }

    UILabel *label = (UILabel *)[cell viewWithTag:1];
	NSString *text;
	text = [textArray objectAtIndex:indexPath.row];
    CGRect cellFrame = [cell frame];
	cellFrame.origin = CGPointMake(0, 0);

	label.text = text;
	CGRect rect = CGRectInset(cellFrame, 2, 2);
	label.frame = rect;
	[label sizeToFit];
	if (label.frame.size.height > 46) {
		cellFrame.size.height = 50 + label.frame.size.height - 46;
	}
	else {
		cellFrame.size.height = 50;
	}
	[cell setFrame:cellFrame];

    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
	UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
        //UITableViewCell *cell = [self cellForRowAtIndexPath:indexPath];
	return cell.frame.size.height;
}

–以上–