你必须重新开始

enter image description here
上一期文章发了以后,很多读者反馈说,为毛不用艾维的头像做封面啊,让我们看看这家伙是怎么虎头虎脑又充满艺术感的。好吧,今天我就截了一张艾维演讲的图给你们瞅瞅,其中他正在碎碎念视网膜屏macbook pro的那点事,刚好说了一句:你必须重新开始。中心思想就是:「哥完全抛弃了老mbp的工艺设计,外部铝合金壳和内部芯片和电路结构全部重新来过,老牛逼了,你看着办,不买是你的损失。」大概就这意思。

我觉得这句话挺好的,正好拿来作为今天的主题,回答之前积累的两个问题。

问题一:

毕业三年,java开发。在青岛拿着4500的月薪,因为兴趣自学了Objective-C,写些iPhone的小demo,没做过实际的项目。很迷茫,有时候想再回北京奋斗两年赚个首付回青岛,但害怕自己中途又受不了北京那压抑孤独的环境再次半途而废,但是在青岛这样下去实在无法安定下来,因为攒不下钱。很迷茫,不知道下一步该怎么走了,求指点。

问题二:

毕业一年,在盛大工作。工作中使用Windows为主,开发,运维,服务器都使用Windows,可我觉得自己还是喜欢玩命令行,喜欢linux,业余时间自己也在看书,学习,但是也没啥成就。请问,我这样坚持下去对本职工作也没啥用(之前目前是),请给点建议吧?

我觉得这俩问题的共性是,对现状不满意,业余时间学了点其他技术,但无法做出改变。之前我提到过《城中大盗》里的一句台词,「你知道吗,人们每天起床,做着同样的事情,他们告诉自己,有一天要改变生活,但他们从来不付诸行动。我想改变自己的生活」。想要改变生活,就要付诸行动,没有更直接的建议了。 我想这两位读者都是「80非常后」,20郎当岁,有想法有激情有大把时间,而且Nothing to lose,所以我的建议就是「尽快重新开始」。想去北京挣首付的,赶紧准备简历和火车票。不喜欢再玩windows的,一边学习Linux,一边找工作是正道。

有时候你必须重新开始,就是这样。

明天周五,打球休息!我不是自媒体人,也不靠这玩意养活自己,就别死乞白赖的写了,你们也都好好歇歇,陪陪家人朋友,别老玩手机了啊。


今天我们接着之前OC的内容,讲讲新的Objective-C在语法层面做了哪些简化。

4、语法简化

很多刚从其他编程语言转到Objective-C的同学看到长长的函数名会感到崩溃,不过我之前也提到过,这种语法让消息的传递像一个英语句子,大大增强了可读性。比如你想初始化一个浮点数,需要这么写:

NSNumber value = [NSNumber numberWithFloat:123.45f];

从这句中我们能够明确的知道代码的含义,但是,是否连简单的赋值语句也要这么处理呢?苹果在本次新特性中采用了折中的处理方式,针对很多基础类型采用了简写的方式,实现语法简化。简化以后,我们会发现从语法层面,这些简化的Objective-C更像Python和Ruby等动态语言的语法了。下面我们逐一介绍:


NSNumber

简化前的写法:

NSNumber *value;
value = [NSNumber numberWithInt:12345];
value = [NSNumber numberWithFloat:123.45f];
value = [NSNumber numberWithBool:YES];

简化后的写法:

NSNumber *value;
value = @12345;
value = @123.45f;
value = @YES;

装箱表达式也可以采用类似的写法:

NSNumber *piOverSixteen = [NSNumber numberWithDouble: ( M_PI / 16 )];
NSString *path = [NSString stringWithUTF8String: getenv("PATH")];

可以分别简写为:

NSNumber *piOverSixteen = @( M_PI / 16 );
NSString *path = @( getenv("PATH") );

对于字符串表达式来说,需要注意的是表达式的值一定不能是NULL,否则会抛出异常。

NSArray

对于NSArray的初始化来说,有非常多的写法,这里就不再一一罗列,我们直接看新的写法

NSArray *array;
array = @[];             //空数组
array = @[ a ];          //一个对象的数组
array = @[ a, b, c ];    //多个对象的数组

非常简单,再也不用记住初始化多个对象的数组时,后面还要跟一个倒霉的nil。

现在我们看一下当声明多对象的数组时,编译器是如何处理的:

array = @[ a, b, c ];

编译器生成的代码:

id objects[] = { a, b, c };
NSUInteger count = sizeof(objects)/ sizeof(id);
array = [NSArray arrayWithObjects:objects count:count];

好吧,编译器已经为我们把这些简单重复的工作都做了,我们就可以安心解决真正的问题了:)不过有一点要注意,如果a,b,c对象有nil的话,运行时会抛出异常,这点和原来的处理方式不同,编码的时候要多加小心。

NSDictionary

同样,对于字典这个数据结构来说,有很多种初始化的方式,我们来看新的写法:

NSDictionary *dict;
dict = @{};     //空字典
dict = @{ k1 : o1 };     //包含一个键值对的字典
dict = @{ k1 : o1, k2 : o2, k3 : o3 }; //包含多个键值对的字典

    最后我们总接一下容器类数据结构简化的限制:

1、采用上述写法构建的容器都是不可变的,如果需要生成可变容器,可以传递-mutableCopy消息。例如

NSMutableArray *mutablePlanets = [@[
@"Mercury", @"Venus", @"Earth",
@"Mars", @"Jupiter", @"Saturn",
@"Uranus", @"Neptune"
] mutableCopy];

2、不能对常量数组直接赋值,解决办法是在类方法(void)initialize进行赋值,如下:

@implementation MyClass

static NSArray *thePlanets;
+ (void)initialize {
    if (self == [MyClass class]) {
        thePlanets = @[
        @"Mercury", @"Venus", @"Earth",
        @"Mars", @"Jupiter", @"Saturn",
        @"Uranus", @"Neptune"
        ];
    }
}

3、没有常量字典

容易的事都让别人做了

noteasy

今天遇到一位读者问技术问题,结果回复的时候发现人家把消息接收关了,那您问的哪门子问题啊,害的我白敲半天字。这个情况遇到好几回了,记住,如果你想收到回复,请把帐号详细资料里的接受消息选上。

最近在帮着几个朋友看项目,发现了一个很有意思的现象。被企业客户蹂躏的不像样子的兄弟,想做面向个人消费者的互联网服务;在个人消费者的市场里或默默无闻或头破血流的开发者,想去企业软件市场试试水。

我想说的是,都不容易,因为容易的事已经被别人做了。另外,个人消费者和企业这两件事,真心没必要割裂来看。

企业客户确实难伺候,比如互联网服务的开发者可以这样:爷就不支持IE6了,爱他喵用不用。而企业软件的客户可以这样:爷就用IE6怎么啦,不支持别想验收。 大家感受下是不是有点不一样。而且企业客户还有两件宝,就像太上老君的金刚圈一样,随时扔出来砸晕你,第一是有问题了要免费的咨询和交流,更牛的直接要方案,别谈钱,谈就远了;第二是开始干活了要专家。哪那么专家,专家都砌砖呢,砌的好的都忙着呢!大家再感受下。

虽然环境恶劣,但仔细分析一下,企业客户是很真实的,你的软件确实帮助他解决了问题,就能够保证自身的现金流,有了现金流,你就可以做其他的事情了。想挣钱,就别怕干脏活累活,创业公司活下去最重要。单纯做互联网当然阳春白雪了,几十万上百万的用户给你虚幻的存在感,但是一旦VC的钱没了,这些存在感就烟消云散了,过去两年里,那么多公司和服务,用着用着就没了。

所以我觉得吧,完全可以以战养战,做做企业软件产品和项目,先自己养活自己,同时积累技术和经验,以期伟大产品的诞生和长治久安。(最近读贝塔咖啡鸦总的文章,他们似乎在走类似的路子,不知道猜的对不对)。

下周谈谈互联网和企业软件的融合趋势,欢迎拍砖。

再推荐三个微信帐号吧,相对人文一点的:
1、贝塔·朋友
betacafe
我记得原来叫贝塔咖啡来着,咋能改名呢?肯定是裙带关系!这个账号由江湖人称鸦总的白鸦维护,沉寂了一段,最近重新出山,基本上每天都更新,而且文章质量有越来越好的趋势,产品内容多一些,现在也谈谈人生扯扯淡。

2、听甘德霜讲故事
igandeshuang
差不多隔天更新,主要说一些八卦的历史话题,偶尔也会说说别的,读起来也蛮有意思的,喜欢历史八卦的关注下。

3、戏里戏外
beyondthewall
互联网有一道墙,但是有那么一扇窗,偶尔透出一丝暖暖的微光。这帐号就干这事,其中的系列法源寺外史很好看。

今天下载了@tinyfool 做的App「新杂志」(还未正式发行),基于iBooks Author相关技术,其中首批创刊号包括了「小道消息」「戏里戏外」「Mac技巧」的部分内容,非常好看。在杂志中Mac技巧更名为「MacTalk」,算是大众一点吧。等正式发行了,我会推荐大家去看看。

今日的MacTalk,讲OC的第三个新特性:属性合成

每个开发人员对property都很熟悉,我们需要为类定义属性,编写getter和setter方法。那么我们在Objective-C中是如何进行处理属性呢?很简单,首先在h文件中定义属性:

@property (strong) NSString *name;

然后在m文件中使用@synthesize指令实现属性的accessor方法和定义实例变量ivar:

@synthesize name = _name;

@synthesize的含义是,如果没有进行重载的情况下,编译器会根据读写属性自动为类实例变量_name生成getter和setter方法。当然,你也可以用@dynamic指令指定该属性的相关方法由开发人员实现。

这样看起来是不是已经很简单了?但是没有最简单只有更简单。现在我们可以省略掉@synthesize name = _name; 这一行,完全交给编译器去实现。也就是说在h文件中声明属性name后,就可以直接在实现文件中使用该属性的getter和setter方法,并使用实例变量_name。并且编译器会根据属性的可读和可写自动判断是否提供setter方法。

那么在这种情况下,如果你声明了@dynamic的属性,编译器该如何处理呢?所有synthesize相关的特性将不再起作用,你需要自己去实现属性的相关方法。

总接一下属性合成的新特性:

  • 除非明确说明,否则属性相关的accessor方法(getter和setter)将自动生成。
  • 除非所有的accessor方法提供实例变量,否则实例变量(例如_name)会自动生成。
  • 如果使用了@synthesize,并没有提供实力变量名的话,会自动生成。
  • 如果使用了@dynamic,那么自动合成无效,需要开发者自己实现。
  • Core Data的NSManagedObject及其子类不使用默认的属性合成功能。

枚举

2013-05-12 10.58.24

如果你以为这是个标题党,那你就错了。今天的内容就是接着昨天的话题讲Objective-C。

想听扯淡的等明天吧。

2、枚举类型的改进

在OS X v10.5之前,我们如何在Objective-C中定义一个枚举类型呢?如下:

typedef enum { 
    ObjectiveC,
    Java, 
    Ruby, 
    Python, 
    Erlang }
Language;

这种写法简单明了,用起来也不复杂,但是有一个问题,就是其枚举值的数据范围是模糊的,这个数值可能非常大,可能是负数,无法界定。

在OS X v10.5之后和iOS中,你可以这样写:

enum {
    ObjectiveC,
    Java,
    Ruby,
    Python,
    Erlang
};

typedef NSUInteger Language;

这种写法的好处是,首先这个枚举的数据类型是确定的,无符号整数。其次由于我们采用了 NSUInteger,可以不用考虑32位和64位的问题。带来的问题是数据类型和枚举常量没有显式的关联。

现在,你可以这样写枚举了:

typedef enum Language : NSUInteger{
    ObjectiveC,
    Java, 
    Ruby, 
    Python, 
    Erlang 
}Language;

在列出枚举内容的同时绑定了枚举数据类型NSUInteger,这样带来的好处是增强的类型检查和更好的代码可读性。

当然,对于普通开发这来说,枚举类型可能不会涉及到复杂的数据,使用之前的两种写法也不会有什么大问题。

源于梦想并始于微不足道

2013-05-12 10.57.34

昨天谈的付费免费和产品创作等内容,仅仅是思想表达,并不是要探讨Mac技巧是否要收费的问题,就目前微信平台的运营模式,即使我们想做收费阅读,也无从收起,所以大家不必介怀,主要看文字内容。

有位叫做「醉染林夕」的读者发表了这样一个观点,很有趣,大家感受下:

来自沉默的大多数:既然收费与否的问题说不清就说一种观点吧。写作分享做好事这种事很多情况下是作者的表达欲在作祟,也就是他并没有因为做了这个可以得到什么而去做,而是他就想做,他想把事情做极致,这可以说是他的命。 连岳有篇文章叫《个人之上再无价值》曾引发了很多人对个人是否要有社会责任的争议,很多人担心如果大家都只看到自己的利益而不去为社会着想,社会怎么进步,或者说社会怎么会快速进步。这里我认为就预设了一个假命题,即大家都为了自己利益。 其实总会有那么一群人为了大家着想的,总会有人不为其他的努力与现状抗争的。毕竟,自私,同情,分享等等美好品质都是人的天性,或者至少说是一部分人的天性,社会自有系统。

我以为这一段写得非常好,再好一点就赶上我了(哈哈)。我认识的好几位技术人做微信公众平台都属于兴之所至,而不是盈利为先,无论是表达欲望也好,创作欲望也罢,大家在无偿的分享自己的经历和思想,这是命。当然如果有一天这些频道和内容衍生出了伟大的事业和财富,我们也不会拒绝,谁会拒绝内容创造的财富呢?这也是命。

所有伟大的事业都源于梦想,并始于微不足道。

Macintosh之父拉斯金的梦想之一是“数以百万计的电脑”,他的远大志向是“如果个人电脑能够真正面向个人,那么任何一个家庭都该拥有一台”。但是Macintosh项目初期,整个项目组只有四名研发工程师,而且每隔一段时间项目就会被拿出来讨论。30年过去了,这个微小的项目组成就了现在的Mac帝国。

另外,昨天推荐的「一天一件艺术品」的微信号有误,错误的原因并不是我记错了,而是下划线被markdown编辑器吃掉了,于是很多读者反馈找不到这个平台。这事我也挺纳闷的,其实只要知道了公众平台的名字,就可以很容易查到这个频道,点击微信底部菜单朋友们-添加朋友-查找微信公众帐号,输入「一天一件」即可。找不到的自个面壁去!

「一天一件艺术品」正确的微信号是:

one_art_everyday

最近扯淡有点多,今天开始从语法层面为大家介绍一些Objective-C的新特性。

去年的WWDC上,苹果针对Objective-C和LLVM编译器都做了重大改进,我们来看一看Objective-C增加了哪些新特性。

1、方法顺序无关

Objective-C类由声明文件h和实现文件m组成,所有的public方法都在h文件中声明,private方法可以写在m文件中,但是在早期的编译环境中需要注意方法的顺序,例如下面的代码,在早期的编译环境会给出警告:

类和方法声明:

@interface ObjcNewFeatures : NSObject
-(void)doSomething:(NSString *) text;
@end

实现:

@implementation ObjcNewFeatures
-(void)doSomething:(NSString *)text{
        NSLog(@"%@", [text stringByAppendingFormat:[selfgetCode]]);
}
-(NSString *)getCode{
        return@"Unicode";
}
@end

早期编译器编译时会出现:warning: instance method ‘-getCode:’ not found…

这是因为根据编译顺序,编译器不知道在doSomething之后还有getCode方法,所以会给出警告。解决办法有多种,比如可以把getCode方法放到doSomething之前,也可以提前声明私有方法,如下:

在m文件中增加:

@interfaceObjcNewFeatures()
-(NSString *)getCode;
@end

新版编译器在LLVM中增加了新特性,改变了顺序编译的方式,首先扫描方法声明,然后再对其实现部分进行编译。这样无论是public还是private方法,就变得顺序无关了。

坚守承诺

promise

申明:在《方恨少》那一期(回复108 可读),我写了这么一句话,“Mac技巧写了这么多期,我觉得我需要更多的积累才能继续输出,我在考虑这玩意是不是也搞个第一季,完结之后重新思考一段时间再继续上路……”

没想到这句话同时引发了微信公众平台“鬼脚七”的共鸣。鬼脚七的微信号是taobaoguijiaoqi,由知名技术人文德运营,他的微博ID是 @淘宝鬼脚七,长期专注于搜索引擎、电子商业。他运营的平台“鬼脚七”主要分享电商资讯、搜索趋势、淘宝动态、产品设计和人文感悟,不知道他哪来那么多的精力,每天更新,文长而有趣,我关注之后,学到了很多好玩有用的知识,推荐给大家。

我俩聊天时想,是否可以类似美剧那样一季一季的写微信平台,这样作者和读者都有个空档期来思考一些东西。遂决定,鬼脚七和Mac技巧这两个公众账号将于2013年4月28日结束第一季,第二季开启时间会在第一季的最后一期文章里说明,这段时间大家有什么建议或者意见,可以随时反馈给我们,非常感谢!

以下正文,今天讲个小故事。

在一场大地震之后,满目都是破坏和混乱,一位父亲安顿好家里其他人之后,跑去儿子就读的学校,但是学校已经被夷为平地,父亲痛苦不堪,但是他想起了对儿子的承诺:无论发生什么,我都会在你身边。于是这位父亲找到儿子所在的教室位置,开始在石砾中挖掘和寻找。

这时候更多的父母赶到学校,他们变得绝望和无助,不停的呼唤孩子的名字,也有好心人过来劝阻这位父亲,一切都太迟了,接受现实吧,回去吧,等等。面对劝阻,这位父亲的回答只有一句话,你们要帮我吗?然后继续一块石头一块石头挖,寻找自己的儿子。

消防队长和警察也开始劝这位父亲,这里还有危险,请尽快离开,我们会处理一切的。但这位父亲的回答是:你们要帮我吗?然后继续寻找。

为了搞清楚自己的儿子是死是活,父亲继续挖掘,在经过30多个小时之后,父亲推开了一块巨大的石头,听到下面有响声,他大声喊着,儿子,是你吗?

这时父亲听到了这一生最美妙的天籁之音:爸爸吗?是我,我知道你会来救我的!

这个教室有30多个孩子,教室倒塌时,刚好形成一个三角形的支架,为其中的14个孩子形成了一道生命的屏障。因为这位父亲,14个孩子幸存下来。

这是我在很久以前的一本叫做《每天读一点英文》的杂志上看到的一则短文,当时印象非常深刻,现复述下来,送给所有坚守承诺和保有希望的人。

今日Mac技巧:

继续介绍OC的Protocol吧。

Protocol一般使用在哪些场景呢?Objective-C里的Protocol和Java语言中的接口很类似,如果一些类之间没有继承关系,但是又具备某些相同的行为,则可以使用Protocol来描述它们的关系。不同的类,可以遵守同一个Protocol,在不同的场景下注入不同的实例,实现不同的功能。其中最常用的就是委托代理模式,Cocoa框架中大量采用了这种模式实现数据和UI的分离。例如UIView产生的所有事件,都是通过委托的方式交给Controller完成。根据约定,框架中后缀为Delegate的都是Protocol,例如UIApplicationDelegate,UIWebViewDelegate等,使用时大家可以留意一下,体会其用法。
 
使用Protocol时还需要注意的是:

1、Protocol本身是可以继承的,比如:

@protocol A
 -(void)methodA;
@end
@protocol B < A >
 -(void)methodB;
@end

如果你要实现B,那么methodA和methodB都需要实现。
 
2、Protocol是类无关的,任何类都可以实现定义好的Protocol。如果我们想知道某个类是否实现了某个Protocol,还可以使用conformsToProtocol进行判断,如下:

[obj conformsToProtocol:@protocol(ProcessDataDelegate)] 

说说我和Mac(二)

Panther-X.3-picture

回复 98 可以看 《说说我和Mac(一)》,今天是二。

我在洪恩软件一共工作了3年半的时间,这段经历让我的能力和见识得到了长足的成长。期间做过互联网(没错,就是传说中的第一波互联网神奇泡沫,一触即溃),基于Perl构建洪恩在线网站;做过企业级软件数字校园,基于Java和Jsp技术;做过英语培训软件,基于.Net和C;还管理过儿童产品事业部。不过让人非常伤感的是,我参与的大部分软件项目都以失败告终,洪恩在线遭遇互联网泡沫,数字校园过于超前,销量一般,英语培训碰到2003年非典,完全无人问津。当时洪恩的主要的业务还是电脑教育、高教、英语、儿童软件等,现金流良好。但安则思变,公司开始尝试其他的业务类型,比如互联网、游戏、企业软件、培训等等,这些项目我基本都参与了,但成者寥寥,这对当时年少轻狂的我来说打击非常大,经常参与失败或无疾而终的项目会让人产生对己对人的怀疑和不自信。

要么留下来继续坚持,要么出走寻找新的挑战,这是很多人当时的选择。有些人选择坚持,有些人选择离开,留下的很多技术人员组成了后来的游戏公司完美时空的技术和策划班底,完美时空2007年在纳斯达克上市,目前发展得非常好。离开的人,则就各自有各自的生活和精彩。

所以说选择这个动作真的很神奇,人生漫漫征途,到处十字路口,每次选择就把你带向一个完全不同的路和沿途的风景,我们只能慨叹,嗟夫,人无常势,水无常形。

当时我选择了离开,那段时间是1999到2003年。在这段时期里,地球的那一边,乔布斯正在重新整肃苹果,在进行了精兵健身并相继推出了iMac和iPod,苹果正在一步步走向巅峰,只不过还没有看看到这家没落帝国的潜力,在国内,Mac仍然是稀有物品,我也仅仅见过两款。(待续)

昨天谈了第一季第二季的想法,有读者回复,一季一季也不错,间歇期间可以出点题目之类让大家投稿,分享大家的想法。
这个思路,我觉得不错。

今日Mac技巧:

说完了Objective-C的Category,今天简单说说Protocol。

Protocol,简单来说就是一系列不属于任何类的方法列表,其中声明的方法可以被任何类实现。这种模式一般称为代理(delegation)模式。你通过Protocol定义各种行为,在不同的场景采用不同的实现方式。在iOS和OS X开发中,Apple采用了大量的代理模式来实现MVC中View和Controller的解耦。
 
定义Protocol很简单,在声明文件(h文件)中通过关键字@protocol定义,然后给出Protocol的名称,方法列表,然后用@end表示Protocol结束。在@end指令结束之前定义的方法,都属于这个Protocol。例如:

@protocol ProcessDataDelegate <NSObject>
@required
- (void) processSuccessful: (BOOL)success;
@optional
- (id) submitOrder: (NSNumber *) orderid;
@end

 
以上代码可以单独放在一个h文件中,也可以写在相关类的h文件中,可以视具体情况而定。该Protocol包含两个方法,processSuccessful和submitOrder。这里还有两个关键字,@required和@optional,表示如果要实现这个协议,那么processSuccessful方法是必须要实现的,submitOrder则是可选的,这两个注解关键字是在Objective-C 2.0之后加入的语法特性。如果不注明,那么方法默认是@required的,必须实现。
 
那么如何实现这个Protocol呢?创建一个普通的Objective-C类,取名为TestAppDelegate,这时会生成一个h文件和m文件。在h文件中引入包含Protocol的h文件,之后声明采用这个Protocol即可,如下:

@interface TestAppDelegate : NSObject<ProcessDataDelegate>;
@end

用尖括号(<…>)括起来的ProcessDataDelegate就是我们创建的Protocol。如果要采用多个Protocol,可以在尖括号内引入多个Protocol名称,并用逗号隔开即可。例如<ProcessDataDelegate,xxxDelegate>
 m文件如下:

@implementation TestAppDelegate
- (void) processSuccessful: (BOOL)success{
    if (success) {
        NSLog(@"成功");
    }else {
          NSLog(@"失败");
    }
}   
@end 

由于submitOrder方法是可选的,所以我们可以只实现processSuccessful。