用NSZombieEnabled解决恼人的EXC_BAD_ACCESS错误

更新Xcode 4设置NSZombieEnabled方法:
按住Option点Run按钮,在出现的窗口中选择Arguments,在Environment Variables里面添加NSZombieEnabled,Value下面添YES

以下为XCode 3的设置方法

这个方法也许很多人都知道了,但是毕竟有不知道的,比如在写这篇文章之前10分钟的我。先说明情况:昨天遇到了这样的问题,程序突然Crash,出现EXC_BAD_ACCESS错误,但是不是每次都Crash,有几次RP高了就好使,Debug时最终基本停在objc-msgsend这里,但也不是每次,是大部分(90%)。十分令人费解,搞了几个小时无果,求助google和stackoverflow终于解决。

首先解释下EXC_BAD_ACCESS,当你向已经释放的对象发送消息时就会出现这种错误。

至于NSZombieEnabled,就是当设置NSZombieEnabled环境变量后,一个对象销毁时会被转化为_NSZombie,个人感觉和线程的那几个状态有些相似,设置NSZombieEnabled后,当你向一个已经释放的对象发送消息,这个对象就不会向之前那样Crash或者产生一个难以理解的行为,而是放出一个错误消息,然后以一种可预测的可以产生debug断点的方式消失(原文是die),因此我们就可以找到具体或者大概是哪个对象被错误的释放了。

设置NSZombieEnabled的方法如下

  1. 在XCode左边那个Groups & Files栏中找到Executables,双击其中的一项,或者右键Get Info;
  2. 切换到Arguments
  3. 这里一共有两个框,在下面那个Variables to be set in the environment:点+号添加一项,Name里填NSZombieEnabled,Value填Yes,要保证前面的钩是选中的。

好了,赶紧去找哪里出了问题吧,至于取消NSZombieEnabled,就是吧刚才提到的那个钩取消即可。

最后总结一下感想,首先是我对EXC_BAD_ACCESS这个错误还没有足够的认识,其次是我没有尽快的去搜索一下解决方法,这两点导致我浪费了大量时间做各种各样奇怪的调试。幸好现在解决了,可以继续工作了。

2012.02.15更新:

在debug过程中,你可能发现启用NSZombieEnabled后,程序不再crash,而一旦去掉NSZombieEnabled,程序再次crash。此时NSZombieEnabled已经无法解决你的问题,只能遵照内存管理原则仔细查找问题出处,至于这种问题的产生原因,个人认为可能是NSZombieEnabled在一定程度上延长了一个object的生命周期,而延长的这段时间恰好突破了EXC_BAD_ACCESS的临界点,从而避免了EXC_BAD_ACCESS的发生。

–以上–

XCode技巧之UserScripts

XCode作为一款强大的IDE,当然也支持脚本功能。通过添加自己的脚本我们可以很方便的完成我们的工作。

在XCode中点击 Edit User Scripts即可方便的添加脚本,而且XCode自带的脚本也相当于给我们提供了丰富的样例。

比如我们添加一个这样的脚本,并为其添加一个快捷键⇧⌘P(快捷键添加方法参考Comments分类中的Un/Comment Selection脚本)

 

#!/bin/sh

echo "%%%{PBXSelection}%%%"
echo "#pragma mark -"
echo "#pragma mark %%%{PBXSelectedText}%%%"
echo "%%%{PBXSelection}%%%"

注意在Output下拉列表中选择Replace Selection。这个脚本的作用是方便我们建立#pragma,首先提供pragma的名字,然后选中这个名字,按相应快捷键,#pragma就自动完成了,很方便。

这个脚本也可以这样写,我们就不用每行都写echo了

 

#!/bin/sh

cat << EOF
%%%{PBXSelection}%%%
#pragma mark -
#pragma mark %%%{PBXSelectedText}%%%
%%%{PBXSelection}%%%
EOF

除了bash脚本,XCode还支持Ruby,Python等多种语言的脚本,比如这个Ruby脚本

 

#!/usr/bin/env ruby -w

# Source: http://allancraig.net/blog/?p=315

properties = ''
synthesize = ''
release    = ''

STDIN.read.each do |line|
	line.gsub!(/\*/, '').strip!
	words = line.split(/\s+/)
	
	label = words.size > 2 ? words[1] : words[0]
	variable = words[-1]
	properties << "@property (nonatomic, retain) IBOutlet #{label} *#{variable}\n"
	synthesize << "@synthesize #{variable}\n"
	release << "[#{variable.chop} release];\n"
end

synthesize << release.chomp

`echo '#{synthesize.chomp}' | pbcopy`
print properties.chomp

该脚本的作用是帮助我们添加@property、@synthesize、还有dealloc方法中相应的release。使用方法是选中.h文件中的成员变量,比如我们选中UIButton *aButton;,复制到要添加@property的位置,再次选中,按快捷键执行脚本,@property就添加完成了,然后到相应的.m文件中,在要添加@synthesize的位置按⌘V粘贴,@synthesize也添加好了,同时复制过来的还有[aButton release];,选中这行,剪切粘贴到dealloc方法中,大功告成。使用这个脚本不仅可以快速添加@property @synthesize,同时也避免了变量名写错所造成的一些问题。

XCode技巧之自定义TextMacros

这篇文章一样,以下基本都是从becoming productive in xcode中取得的

===Text  Macros===

添加自己的TextMacros(XCode 3.2.5测试通过,XCode 4 未测试)

在~/Library/Application Support/Developer/Shared/Xcode/下面新建Specifications文件夹,建立与/Developer/Applications/Xcode.app/Contents/PlugIns/TextMacros.xctxtmacro/Contents/Resources文件夹下类似的*.xctxtmacro文件即可

例子

 

(
  {
    Identifier = objc.hello;
    BasedOn = objc;
    IsMenuItem = YES;
    OnlyAtBOL= YES;
    Name = "Hello";
    TextString = "Hello, XCode!";
    CompletionPrefix = "hello";
    IncludeContexts = ("xcode.lang.objc");
  },
  {
    Identifier = objc.property;
    BasedOn = objc;
    IsMenuItem = YES;
    OnlyAtBOL= YES;
    Name = "@property Definition";
    TextString = "@property (nonatomic, retain) IBOutlet <#type#> *<#variable#>;";
    CompletionPrefix = "prop";
    IncludeContexts = ("xcode.lang.objc.interface");
  },
  {
    Identifier = objc.rectmake;
    BasedOn = objc;
    IsMenuItem = YES;
    OnlyAtBOL= YES;
    Name = "RectMake";
    TextString = "CGRect aRect = \n\tCGRectMake(<#x#>, <#y#>, <#width#>, <#height#>);";
    CompletionPrefix = "cgrm";
    IncludeContexts = ("xcode.lang.objc.block");
  }
)

上面的代码添加了三个textmacro:

第一个仅仅是测试用,代码中输入hello即有自动补全提示,补全成Hello,Xcode!。

第二个效果是输入prop,然后 ⌃. 自动补全成@property (nonatomic, retain) IBOutlet <#type#> *<#variable#>;的形式,具体实验一下就知道了。

第三个类似,不多说了。

首先注意一下OnlyAtBOL这一行,在新版本的XCode中如果不加上这一行则textmacro无法生效。具体请看这一段的解释:

There is a bug on TextMacros in the latest versions of Xcode (I encourage you to send a bugreport to Apple as I did)

In fact, only TextMacros that have the value “YES” for the key “OnlyAtBOL” will work. If this key is not present (or set to NO), the macro will not respond to autocompletion.
Actually, the new “OnlyAtBOL” key means “Only at Beginning Of Line”, so the autocompletion for this macro will only work if it is triggered in the beggining of a line. But in fact, quite every macro I need everyday comply to this constraint (ifelse, nslog, nss, …) so this is acceptable.
If you want those macros (that does not work because of the lack of OnlyAtBOL set to YES) to work again, you need to add/override their specifications in your “Application Support” directory (in a custom TextMacro file that override them), until the Xcode team fixes that bug.
 
 

XCode快捷键及小技巧

首先推荐个视频:Becoming Productive in XCode  链接里有个demo版的,完全版是收费的,处于对源作者的尊重,不放出下载地址,各位同学自行解决,推荐有能力的购买一下,还是物有所值的,下面这些基本都是视频中提到的

—Workspace—

⌘N          New project

⌘,             Preference

 

⌘E          Zoom editor in

⌥⇧⌘E       Zoom editor in fully

 

—文件切换—

⌘← →     历史编辑点切换

⌘D          Open Quickly,直接输入文件名,支持查看各种.h .m …

⌘↑          .h与.m切换

 

—File Navigation—

← →         按word移动光标,向右移动到word尾部,向左移动到word头部

⌘← →         移动到该行头/尾,

⇧⌥← →      高亮word

⌘← →      高亮行

⌘↑ ↓            移动到文件头/尾

L               光标所在行放置在编辑器中间

⌘L               Goto(行号)

 

2               打开method列表(应该叫Function Popup)(与系统的Spaces切换有冲突,看自己习惯了)

⌘D              BookMark

4               BookMark列表(BookMark Popup)

⌘M          打开Bookmarks Smart Group

 

⌘F              搜索

⌘G ⌘G   (搜索中)下一个/上一个

⌘F           跨文件搜索

+双击        以浮动窗口形式查看定文档

⌘+双击     查看相应文档

 

—Editing Source Code—

TAB             确认当前补全

  ,        补全列表

/               切换到下一个Placeholder

 

⌘←   →    折叠、展开代码段

⌘↑ ↓         折叠、展开所有method段

⌃⌥⌘F        打开、关闭当前代码段高亮功能

 

⌘/               快速注释、取消注释

⌘T           同时编辑当前文件中所有同一变量名

 

—Refactoring—

⌘J           Refractor对话框

 

—Building and Running—

⌘B              Build

⌘B           Build Result窗口

⌘=  ⌘=    查看warnings、errors

⌘Enter         Build & Go

⌘R           打开Console

⌃⌥⌘R        Clear Console      

 

⌥⇧⌘/        打开文档(这是快捷键么)

 

====Tips====

 

—Workspace–

分组(Group)是任意的,并不会真的产生这个目录

Smart Group很实用

右上角那个搜索是支持通配符和正则表达式的,点击放大镜边上的箭头

 

—File Navigation—

类似列表的东西都是支持键盘输入开头的几个字符来选择相应项目的

#pragma mark [something]     类似分隔线的东西,效果在Function Popup中可见,尤其是 #pragma mark – 的时候

 

// TODO: [something]

// MARK: [something]

// FIXME: [something]

// !!!:

// ???:

以上均可在Function Popup有相应效果

 

Editor部分右上角那个右边带箭头的C按钮 打开可查看Superclass(Navigator popup) 默认无快捷键

 

—Refactoring—

Extract:Refactor那个对话框的另一个功能是Extract 支持自动把当前函数中的一段提取到一个新的函数中,对代码重构很有用。使用方法:选择要提取的部分,按⌘J,选择Ectract,然后修改一下函数名即可,系统已经自动把所需的参数添加好了。 

 

—Building and Running—

Preference 》Debugging 》On Start 选择 Show Console 可以默认打开Console

[AppleScript] 小技巧:执行sudo的方法

AppleScript是个强大的好东西,虽然我只是用它来执行一些命令行操作(呃,实际上我还没学怎么进行别的操作),好了废话不多说了,直接进入主题。

在AppleScript中执行终端操作的方法:

    do shell script "SOME COMMANDS"

很简单吧,如果要有管理员权限怎么做,人们自然想到要这样:

    do shell script "sudo SOME COMMANDS"

但是运行一下会出现这个提示:

    AppleScript 错误

    sudo: no tty present and no askpass program specified

解决方法很简单,不要直接把sudo加到里面,而是改成这种形式

    do shell script "SOME COMMANDS" with administrator privileges

这样运行的时候就会弹出那个提示输入管理员密码的那个对话框,sudo的问题就解决了

 

[教程]共享本机代理给其他设备

由于某些众所周知的原因,本文风格可能有些委婉,还请各位谅解。

     有些代理程序只能给本机使用,比如那些默认地址是localhost:port这样的,要把这种只针对本地的代理共享给其他设备尤其是iphone,touch,ipad,android等移动设备就有些麻烦了。笔者认为其中一个可行的方法就是搭建一个服务器,比如apache之类的,再设法把网络请求通过本机的代理发送(大概就是这个意思吧,我也描述不太好)。但是我只实现了搭建服务器这一块,不知道怎么实现后面那部分,要是高手看到这还请多多指教。

    好了言归正传,既然有难度的弄不明白,总有简单的方法,只需要Charles Web Debugging Proxy这个软件即可实现。这个软件夸Mac Linux Windows三大平台,有30天试用期,希望广大同学多多支持正版。

    软件针对本文的使用方法:菜单:Proxy  >>  External Proxy Settings…,勾选 Use External Proxy Serves,在下面即可设置代理,注意到这里还可以设置socks代理,因此可以通过Charles把代理共享给不支持socks代理的设备。

    在Proxy >> Proxy Settiongs下面可以设置对外的端口,默认是8888,设置好之后就可以把代理共享给其他设备了。

Have Fun

-以上-

(转载)屏幕范围快照”Command + Shift + 4”功能补全说明

 

日本わかばマークのMacの备忘录网站针对Mac作业系统屏幕范围快照功能做了补充介绍,向来Mac使用者除了熟知组合键”command + shift + 3”全屏幕快照功能外,拖曳屏幕范围的快照功能”command + shift + 4”也相当实用,这里就”command + shift + 4”的补充功能进行说明。

 

 

相关的图示范例请参考原文,只要熟记组合键的应用,对于屏幕撷取的需求有相当助益;友站ApplePlan另整理了相关的快照进阶技巧,亦欢迎参考。

基本功能

     透过组合键,拖曳游标范围后,就能针对范围进行屏幕快照。

     透过组合键,按一下空白键后,再点按一下滑鼠键(click),即能针对单一执行中的视窗进行快照。

辅以option键

      再按下组合键后,先按住option键,屏幕拖曳范围的起点就能更灵活定位。

辅以shift键

      再按下组合键后,请先不要放开拖曳中的游标,确定范围的横(宽)或纵向(高)尺寸后,这时只要按住shift键,横向移动游标即能针对同样的高度延伸屏幕快照范围;反之,按住shift键后,纵向移动游标,即能针对同样的宽度,延伸所需的萤幕快照高度。

辅以space空白键

    按下组合键,并且确定屏幕快照的范围尺寸后,这时若按住空白键,屏幕快照范围能提供固定尺寸、随意的移动。

 

Mac下为iTunes U添加字幕的方法

iTunes U的介绍等废话就不多说了,直接进入主题,使用一个叫iSubtitle的软件即可搞定,当然你还要有相应的字幕文件才行。经笔者测试,虽然该软件输出的文件为mov格式,但是itunes仍然可以正确识别并分类。支持字幕开关,不损坏原来的文件。同时支持iPod等设备,字幕效果也很赞,输出速度快,不支持批量操作算是一大遗憾,总体来讲还是很不错的。对于iTunes上下载的正版电影笔者没有条件测试,据说是不行的,有兴趣的可以尝试,软件的具体使用方法参见帮助,下载地址(2.3中文版),有问题请留言。

(END)

Mac OS 下命令行编辑plist的方法

    一般我们编辑plist文件都是直接打开,用PlistEditor什么的进行可视化编辑,但是如果想用脚本编辑plist文件就要用到命令行了,其实这是一个很简单的命令:defaults

    defaults 命令的帮助如下

'defaults' [-currentHost | -host ] followed by one of the following:

  read                                 shows all defaults
  read                         shows defaults for given domain
  read                    shows defaults for given domain, key

  read-type               shows the type for the given domain, key

  write            writes domain (overwrites existing)
  write            writes key for domain

  rename 
   renames old_key to new_key

  delete                       deletes domain
  delete                  deletes key in domain

  domains                              lists all domains
  find                           lists all entries containing word
  help                                 print this help

 is (  | -app  | -globalDomain )
         or a path to a file omitting the '.plist' extension

 is one of:
  
  -string 
  -data 
  -int[eger] 
  -float  
  -bool[ean] (true | false | yes | no)
  -date 
  -array   ...
  -array-add   ...
  -dict     ...
  -dict-add  

 

    光看这些就大概知道怎么弄了吧,下面是几个例子:

defaults read com.xxx.xxx // 输出文件中所有信息
defaults write com.xxx.xxx   // 改变某个key的value,如果没有该key则添�

 

    注意:在 "com.xxx.xxx" 之后没有 ".plist",开始我犯了这个错误,弄半天不知道为何plist文件中的值没有改变。

   (END)

修改Mac下粘贴并匹配样式的快捷键

    Mac下的粘贴功能很“智能”,可以把原来的格式文字原封不动的搬过来,但这样也照成一些麻烦,如乱码,格式混乱等,Mac下还有另一种粘贴方式即“粘贴并匹配样式”(Paste And Match Sytle),这种粘贴方式所”匹配“的样式不是原文的样式,而是要粘贴到的位置的样式,但这种粘贴方法要同时按下“⇧⌘⌥V”这四个按键,实在是有点困难,而对我来讲还是这种粘贴方式更加符合我的工作习惯。解决方法很明确,就是将两种粘贴方式的快捷键互换一下,这样能很好的保证不会与其他快捷键有冲突,方法如下:

  1. 打开 偏好设置>>键盘>>键盘快捷键
  2. 在左边的列表里选择“应用程序快捷键”,然后点下面那个“+”号添加一项
  3. 在弹出的对话框中,“应用程序”选则你要修改的程序,尽量不要选择全部程序,因为某些程序没有匹配样式并粘贴这个操作(比如终端,Mac QQ等),这样就会导致粘贴时必须按⇧⌘⌥+V才行(如果一定要选择所有程序,要么就单独为那些出问题的程序把粘贴这一操作的快捷键设置成⌘+v,要么就使用别的快捷键),“菜单标题”输入“粘贴”,“键盘快捷键”⇧⌘⌥+v,点添加。
  4. 再用相同的方法添加“粘贴并匹配样式”,快捷键“⌘+v”,如果某些英文软件不支持中文,还要添加“Paste”和“Paste And Match Style",方法类似。

    OK,修改完成,现在可以开个程序试试修改的效果了。(END)