好久没写博客了,之前还打算把毕业设计中涉及到的两个算法拿出来说说(脸型分析 + 声音分析),博文都写了一半了,后来实在太忙了,那篇
随笔也就沉在草稿列表中没动过。
我原先是专职 .net 开发的,在公司负责的项目是内部自用的销售管理系统,由于不需要出去"抛头露脸",所以公司干脆什么也没配置(指产品、设计、前端等等,开发设备还是有的),于是所有
工作全包了。原本对自身的计划是,后续会慢慢转产品方面的。
后来,也算是一个契机,公司所有
移动端的人基本走光了(iOS 全走了,
Android 的好像只剩 2 个!!公司内部的事,这里就不多说了),于是上头经理就打算让我们转到移动端开发。.net 和
java 一直都是"死对头"(自己的理解,求别喷),所以我不会选 Android,WP 市场还不够,转过去对自己竞争力的提升不大,于是乎选择了 iOS 开发,于是乎便有了这篇《.net 码农转战 iOS - 初探》。。。
大学时期有一点 C 的基础,但是对 OC 完全不知,这次属于从 0 开始(不选择 swift 开始,其实是怕它还不够成熟。语言这东西,其实说到底是相通的,理解了基础的东西,还怕以后学不会其他的么!)。
我是属于自学的,看视频、查资料一步步慢慢走。
学习真的需要动手敲键盘,单单只是看一下是记不住理解不了的,至少我还没到那个看看就会的地步。。。
· 我从 xcode5 开始,这时候已经少了很多内存管理的代码了(基本不用写 release 了),但是不需要你写,并不代表不需要你了解。所以内存管理需要详看。
· 命名空间,OC 里是没有这个概念的。区分两个不同的类,仅仅是依靠类名。所以一般都会在真正类名前,加一个前缀用来区分,例如 NSString(NS 开头的代表为 MAC OS X 的核心,即 NeXTSTEP 的缩写)、CGPoint。。。许多程序员都会使用自己名字的缩写做类的前缀。
· OC 大量使用指针,而且需显性表示(NSString *str; str 是一个指针变量,前面需加一个 "*" 显性体现,表示它是一个指向 "字符串" 的变量)。.net 中也有这个概念,只是不需要显性表明("*"),参考 .net 中,类、string 的声明。
· @"",OC 中字符串的写法,前面必须加一个 "@" 表示是 NSString 类型;
· NSLog() 方法,即 .net 中 Console.WriteLine 方法,支持字符串的 Format,例如 NSLog(@"%@, %i, %f", @"1", 1, 1.0);(@"%@" 功能很强大,类似于 .net 中 ToString() 方法)。
· 类的声明,创建一个普通的类,包含一个 .h 文件和一个 .m 文件(例如 SLTest.h & SLTest.m),是成对出现的,.h 文件为头文件,一般用来做类的声明,类似 .net 里的抽象类;.m 文件为实现文件,用来实现对应的"抽象类"。
/** SLTest.h **/ //使用import引入头文件 //Foundation为基础框架 //import表示该头文件只被包含一次,无论该命令在整个程序中出现多少次 #import<Foundation/Foundation.h> //用interface标明是类的声明 //该类继承自NSObject,类似.net里的基类object @interfaceSLTest:NSObject { //声明成员变量 } //声明公有方法 @end /** SLTest.m **/ //使用import引入头文件 #import"SLTest.h" //implementation标明是类的实现 @implementationSLTest //定义、实现私有方法 //实现公有方法 @end |
· OC 中声明类使用 interface 关键字,实现类使用 implementation 关键字。其实 OC 中还有一个关键字 "class",它并非 "声明类" 的意思,而是 "包含类" 的意思。功能与 import 相似,但使用 import,编译时会将 import 的文件整个包含进来,而使用 class,编译时只是告诉它已经有这个类,而不会整个包含进来,比 import 更轻量级。多用在只需要知道类名,而不需要使用类中方法的地方(例如变量声明等)。使用方法:@class SLTest;。最大好处,例如有两个类:A、B,A 中有一个变量 B b;,B 中有一个变量 A a;,如果使用 import,那么编译时就是"我中有你你中有我",互相包含,最后造成包含的死循环。
· OC 中方法的调用是使用 "[]",例如 [aaa AAA],在 .net 中即表现为 aaa.AAA(); 。有参数的方法调用例如 [aaa BBB:1 CCC:2],在 .net 中表现为 aaa.BBB:CCC:(1, 2); 。注意,OC 中 ":" 也是方法名,有多少个 ":" 表示有多少个参数,而参数的传入是嵌套在方法名中的(怎么定义怎么用,例如刚才有参数的方法,定义为 -(void)BBB:(NSInteger)i CCC:(NSInteger)j;),这点和 .net 有很大的不同。
· 实例化一个对象,由于要考虑到内存管理问题,OC 中基本都是用 alloc + initXXX 方法(也有个别使用其他工厂模式方法,在此不包括),alloc 表示分配内存,initXXX 表示初始化。基本使用方法:[[NSString alloc] initWithFormat:@"this is a string."]。这里的意思是实例化一个 NSString 对象,指向 "this is a string." 的内存块(initWithFormat:() 是 NSString 自有方法,其他类型也有类似的 initXXX() 的方法,也有的只有 init() 方法)。当然 OC 也有 new() 方法,但是不建议使用。还是 .net 的 new() 好用!!OC 中没有重载,只能用方法名来区分。例如 NSString 中的 initWithFormat() 方法和 initWithCoder()。还是 .net 的 new() 好用!!
· get/set 方法,.net 中我们是使用 { get; set; } 让编译器自动为我们添加,OC 也有类似的:
// 使用 property 关键字声明 // 括号内指定该属性的形式: // nonatomic 表示线程不安全的,在单线程不考虑线程安全的情况,使用 nonatomic 就可以了,对应的 atomic // 一般基础类型用 assign,NSString 用 copy,其他用 strong(retain),当然,凡事也有例外,具体自行谷哥吧 // 此外还有 readonly、getter 等等,自行谷哥吧 @property (nonatomic, assign) BOOL balabalabala; |
只需要这句话,编译器会自动生成私有的成员变量和对应的 get/set 方法,当然也可以自己重写 get/set 方法,在 .m 文件中实现即可。
· 方法前面,"-" 表示是实例方法,即由实例调用;"+" 表示是类方法,即 .net 中类的静态方法。
· OC 中的 id 类型,弱类型,类似 js 里的 var,硬要跟 .net 挂钩的话,很像 dynamic,但貌似又跟 dynamic 有所不同,请原谅我蹩脚的表达能力。。。
· self 关键字,即 .net 中的 this 关键字;super 关键字,即 .net 中的 base 关键字。
· block,也就是 .net 中的匿名函数,定义顺序是:返回类型、"^"关键字、方法名(若声明位置是方法参数,可省略)、参数列表,例如:
// 返回类型为空 // 方法名为 TEST1 // 参数列表为空 void (^TEST1)(void) = ^ { NSLog(@"TEST1"); }; TEST1(); // 返回类型为 NSString * // 方法名为 TEST2 // 需传入一个 NSInteger 类型的参数 NSString *(^TEST2)(NSInteger) = ^(NSInteger i) { NSLog(@"TEST2 parameter: %i", i); return @"test2"; }; NSString *result = TEST2(10); NSLog(@"%@", result); // TEST3 方法定义了一个 block 参数,该 block 无返回值,需传入一个 NSString 类型的参数 - (void)TEST3:(void (^)(NSString * parameter))block { NSLog(@"TEST3"); // 调用 block,并传入参数 block(@"TEST3 parameter"); } // 调用 TEST3,传入 block [self TEST3:^(NSString *parameter) { NSLog(@"parameter: %@", parameter); }]; |
用法同 .net 的无异,只是语法不同。
· category,扩展,即 .net 中的类扩展,例如 public static bool IsValidEmailAddress(this string str);。OC 中,只允许扩展方法,写法:
/** NSString+Category.h 文件命名方法,OC 建议是原类名+扩展名 **/ // 声明时,原类名后加一个括号,括号里为扩展名,表示这是一个扩展 @interface NSString (Category) // 扩展一个方法,判断该字符串是否为 Email 地址 - (BOOL)isValidEmailAddress; @end /** NSString+Category.m **/ @implementation NSString (Category) // 实现方法 // 请忽略具体方法,这里只做演示 - (BOOL)isValidEmailAddress { return [self length] % 2 == 0; } @end // 使用时,引入 .h 文件,即可像普通类方法一样使用 NSString *str1 = @"1"; NSString *str2 = @"11"; NSLog(@"%i", [str1 isValidEmailAddress]); NSLog(@"%i", [str2 isValidEmailAddress]); |
· delegate,协议,注意,这里并不同 .net 中的 delegate,.net 中的 delegate 应该更类似 OC 中的 block。这里的 delegate 更像是 .net 中的接口。用我自己的理解来说,就是我有时候会触发某个事件,而你如果需要知道我何时触发了事件,那么我们之间就必须有一种 "约定协议",即当我触发事件时,通知你。而你收到我的通知后,要干嘛,那是你的自由了。
这里所说的 "约定协议",即 OC 中的 delegate。我要通知你,即使用 delegate 中的方法。你只需要实现这个方法,我就可以通知到你。这个在下一篇再进行详细说明。
OC 的一些基础的东西就差不多了,接下来就是结合到界面的开发,形式很像 .net 的 winform 开发,iOS 中使用 MVC 框架,所以如果你 .net 会这两样的话,还是比较容易看得懂的。
做一款像样的 App,需要各种岗位的同事帮忙,从需求,到设计、编码、测试、上线,确实考验一个团队的合作能力。