标签存档: Objective-C

[笔记] Objective-C 中模拟泛型及 Xcode 格式化代码插件

记录一些 iOS & OS X 开发过程中学到或有趣的东西。

Objective-C 中模拟泛型

今天看到的一个辅助代码,可以在 Objective-C 代码中添加泛型的支持:

泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部份,那些部份在使用前必須作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。(via )

泛型一般出现在 .NET、Java 或 C++ 的代码里面。

在 Objective-C 里面,像数组之类的容器,在取单个元素时,返回类型都是 id,这个时候如果要使用返回对象的一些属性,就需要先转换一下类型,或者使用 getter 方法来获取。

如果用了泛型之后,就很方便了,可以直接以 arr.lastObject.prop 的方式来访问。

使用了上面这个代码使 Objective-C 支持泛型后,就可以像下面这样写代码了:

generics example

这个辅助代码是一个大宏,给 Objective-C 添加泛型支持是以以下几个方面来做到的,例如给 MyClass 添加泛型支持来说明:

  1. 定义一个 MyClass 的 Protocol
  2. 给各个容器类(例如 NSArray、NSMutableArray、NSSet)添加 Category,重新定义各个容器操作方法的返回值和参数类型
    1. 获取单个元素的方法返回值类型修改为 MyClass *
    2. 返回容器的方法返回值类型修改为 NSArray<myclass> *
    3. 参数类型同样处理

这样在使用 NSMutableArray</myclass><myclass> *arr 这样一个变量时,如果添加的元素不是 MyClass * 类型,就会发出警告了。

不过因为 Objective-C 在编译时并不会强制要求变量类型一致,所以如果传递一个非 MyClass *类型的参数,也是可以编译通过的。

当然这个库只能说是在一定程度上方便编写代码而已,至于用不用还是见仁见智了,每次要写 NSArray</myclass><myclass *> 也不见得更方便。

Xcode 代码格式化插件 BBUncrustifyPlugin

插件地址:

这个插件算是对 uncrustify 的一个快捷引用了。

可能会比 Xcode 自带的 Re-indent 功能强大一点点 :)

另外,还有一个图形化的参数配置工具,可以用来配置 uncrustify 那好几百项目的参数:UncrustifyX

参考资料

  1. http://iosdevelopertips.com/objective-c/generics-in-objective-c.html
  2. https://github.com/tomersh/Objective-C-Generics
  3. https://github.com/benoitsan/BBUncrustifyPlugin-Xcode
  4. http://zh.wikipedia.org/wiki/%E6%B3%9B%E5%9E%8B
  5. http://uncrustify.sourceforge.net

—EOF—

在 Ubuntu 中使用 GNUstep 搭建 Objective-C 开发环境

GNUstep 介绍见

安装相关程序

直接 apt-get install 搞定。

  • build-essential
  • gnustep
  • gnustep-devel
  • gnustep-examples
  • gobjc
  • gobjc++

设置环境变量

为了方便使用 GNUstep 的各种编译工具,需要先在 .bashrc 中导入 GNUstep 的脚本。

# Setup GNUstep
GNUSTEP_MAKEFILES=/usr/share/GNUstep/Makefiles
export GNUSTEP_MAKEFILES
source $GNUSTEP_MAKEFILES/GNUstep.sh

编写 Makefile

使用 Makefile 来编译 Objective-C App,注意 Makefile 的文件名为 GNUmakefile

include $(GNUSTEP_MAKEFILES)/common.make

APP_NAME=HelloWorld
HelloWorld_OBJC_FILES=test.m 

include $(GNUSTEP_MAKEFILES)/application.make

这个是编译出 Mac OS App Bundle 形式的目标,如果是编译命令行工具的话,可以使用如下 Makefile:

include $(GNUSTEP_MAKEFILES)/common.make

TOOL_NAME=HelloWorld
HelloWorld_OBJC_FILES=test.m 

include $(GNUSTEP_MAKEFILES)/tool.make

在编译命令行工具时,AppKit 就不会自动链接进来了,使用 NSColor 这样的类就会有问题。

HelloWorld

一个最简单的 HelloWorld 代码:

#import <foundation /Foundation.h>

int main() {
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    NSLog(@"HelloWorld");
    [pool release];
    return 0;
}

保存为 HelloWorld.m,编写 Makefile:

include $(GNUSTEP_MAKEFILES)/common.make

APP_NAME=HelloWorld
HelloWorld_OBJC_FILES=HelloWorld.m 

include $(GNUSTEP_MAKEFILES)/application.make

保存 Makefile 为 GNUmakefile,执行 make,会在当前目录生成 HelloWorld.app,使用 openapp 命令运行:

openapp ./HelloWorld.app

当然如果是编译成命令行工具的目标的话,会在当前目录的 obj 目录中生成 HelloWorld 可执行文件,这个可以直接从命令行运行:

./obj/HelloWorld

参考资料

  1. http://www.gnustep.org
  2. http://www.qiongbupa.com/archives/678
  3. http://www.gnustep.org/resources/documentation/User/GNUstep/gnustep-howto_4.html#SEC8
  4. http://www.gnustep.it/nicola/Tutorials/WritingMakefiles/node6.html
  5. http://www.gnustep.it/nicola/Tutorials/index.html

— EOF —

在 Mac App 中支持全屏和文件版本控制

前言

在 Mac OS X 10.7 Lion 中,新增了两个特性对用户来说可能比较有用的特性,一个是全屏程序,一个是文件版本控制。

全屏程序可以使用户集中注意力到一个程序上,并且隐藏菜单栏、Dock 等不相关的界面元素,使得工作区最大化,更加有效地利用有限的屏幕空间。

文件版本控制可以让用户在不借助于 Time Machine、Git 或者 SVN 这些工具的时候,也可以轻松恢复文件到之前保存过的版本,防止一些误操作删除了重要内容。

全屏程序

全屏功能可以让程序以全屏方式显示,这样用户可以拥有最大的操作区域,并隐藏与程序无关的视觉元素。

在全屏方式下,Dock 和菜单栏都会自动隐藏,可以通过将鼠标移动到屏幕边缘的方式来重新显示 Dock 或者菜单栏。

目前全屏程序有一个问题是在使用双屏的情况下,有一个屏幕会无法使用,只能显示背景图片,而不能同时使用两个屏幕,或者将另外一个程序全屏在另一个屏幕。

另外,全屏程序切换是使用水平动画切换,对我来说可能动作太大,不是很习惯,这是题外话了。

要设置一个 App 支持全屏很简单,只需要设置对应 Window 的属性即可。

Full Screen 有两种模式,分别为 NSWindowCollectionBehaviorFullScreenPrimaryNSWindowCollectionBehaviorFullScreenAuxiliary,其中多数时候只需要使用 NSWindowCollectionBehaviorFullScreenPrimary 即可。

在设置 NSWindowCollectionBehaviorFullScreenPrimary 后,就会在相应的 Window 右上角显示一个全屏按钮,用户通过这个按钮就可以切换程序到全屏方式使用。

全屏模式切换菜单

有些时候,为了用户使用方便,需要设置一个快捷键,或者菜单来供用户进行全屏模式的切换,这时,只需要添加一个 NSMenuItem 到主菜单的 View 菜单中,将 selector 连接到 First Responder 的 toggleFullScreen: 即可。

Cocoa 在运行时会自动寻找 View 菜单中 selector 为 toggleFullScreen: 的菜单项目,并根据当前窗体的显示情况来自动更新菜单标题为 Enter Full Screen 或 Exit Full Screen。

文件版本控制

在 Lion 中对普通用户来说,一个非常有用的特性就是文件版本控制了。在不需要 Time Machine,不需要 Git、SVN 等版本控制参与的情况下,只需要程序支持这个功能,就可以直接找回编辑过文件的以前版本。

在文件版本控制之后,其实是自动保存功能在起作用,要实现文件版本控制,只需要 Mac App 实现自动保存即可,文件版本的控制会有框架来做,不需要开发者过多参与。

对于 NSDocument based 的 Mac App 来说,要实现文件自动保存,一般情况下,只需要在 NSDocument 的子类中实现以下方法就行了:

+ (BOOL)autosavesInPlace {
    return YES:
}

当然,这是在 Mac App 中,是以 NSDocument 提供的诸如 - (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError 或者 - (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError 来保存文件内容为基础,而不是自己去实现写文件内容到磁盘,那样的话就算有 autosaveInPlace 也是不行的。

另外,同样需要使用 - (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError 等 NSDocument 提供的 API 来获取内容。

另外,在 NSWindowDelegate 也有一些新的方法,可以控制程序在浏览文件的以往版本时,控制程序窗口的样式,例如大小,设置控件的状态等。例如,在默认情况下,浏览文件以往版本会改变当前文档窗口的大小,而如果不想修改文档窗口大小,只是缩放显示的话,可以在 window:willResizeForVersionBrowserWithMaxPreferredSize:maxAllowedSize: 方法中指定窗口要变化到的目标大小:

- (NSSize)window:(NSWindow *)window willResizeForVersionBrowserWithMaxPreferredSize:(NSSize)maxPreferredFrameSize maxAllowedSize:(NSSize)maxAllowedFrameSize {
    NSSize winSize = [window frame].size;
    return winSize;
}

NSWindowDelegate 的 Managing Presentation in Version Browsers 一节中,还有另外一个 delegate 方法,可以得知当前文档窗口正在进入版本浏览,或者退出版本浏览等状态,从而可以设置界面控件,将一些无关的界面元素隐藏,使用户可以更加清晰的观察到文件不同版本之间的差别。

要实现文件版本控制的支持,开发者并没有很多工作需要做,多数功能已经由框架实现。

参考资料

— EOF —