首页 文章 精选 留言 我的

精选列表

搜索[翻译工具],共10000篇文章
优秀的个人博客,低调大师

使用 Swift 构建一个 iOS 的邮件应用 【已翻译100%】

在前几个月内,我一直在做InboxKit的研究,它是关于Inbox平台的IOS SDK。Inbox为和邮件数据的交互提供高层API,使得你可以忽略IMAP,Exchange,MIME的解析以及thread探测(当然还有很多其他事情...),并使你致力于完成富有创意的APP的创作上。我们的目标很简单:尽可能地打造一个优雅的,跨提供商的邮件应用。毕竟,它很难。 在Objective-C中,InboxKit使得创建邮件体验变得很轻松,那么,Swift又如何呢?Swift在WWDC后已正式被IOS社区所采纳,我认为以后的SDK设计肯定会包括既有Objective-C又有Swift写的样例。 我们的第一个Swift例子,我想写一个简单的app,它就像一个魔幻8球:1.显示Inbox中未读thread 2.当你摇动手机,标记thread为已读并显示新的thread (译者注:文中的thread并不是线程的意思,在论坛中的一个帖子叫thread,回复叫post.这里可理解为一封邮件)**在 Swift 中使用 Objective-C SDK** InboxKit有6000行Objective-C代码,我们还不打算把他们都转换成Swift。为了编译我们的Swift邮件应用,我更新了open-source SDK,包含了“Xcode 6 自定义框架“。自定义框架是Xcode6的新特色-支持第三方框架的创建和分发。当DEFINES_MODULE标志设置为可用时,自定义框架会自动为Swift准备Objective-C模块的头文件。在Swift编译时,它会读取这个模块头文件,把Objective-C的类和方法映射到Swift。 Cocoa Touch框架包含这个SDK之后,在Swift中使用很简单。比如我创建了一个新的Swift应用,只需要把这个SDK拖入工程中,然后在root view controller中添加import InboxKit。 Xcode 6 自定义框架非常棒, 可是目前只有Xcode 6和iOS 8支持. 如果你正在开发一款应用程序, 你仍然可以选择pod InboxKit。 查看邮件InboxKit 让我们从Inbox同步引擎获取邮件数据变得简单起来。我们实例化一个 INThreadProvider ,以此展示来自我们邮箱账号的线程,并且具象化需要的数据。供应者模型 是InboxKit的一个核心概念: 他们被用于获取线程,信息,联系人和更多东西的集合 。供应者有点类似于Core Data中的 NSManagedObjectContext 和 YapDatabase的视图——他们把复杂的东西封装在内部,只是暴露出一个结果集,这个结果集是基于你提供的配置。 在InboxKit,供应者从本地SQLite store拉取缓存数据,同时,让对于Inbox API 的询问变得透明。 我们的应用将展示来自Inbox的未读线程,每次一个,所以我们这样定义线程供应者: var provider:INThreadProvider! = namespace?.newThreadProvider(); provider.itemFilterPredicate = NSComparisonPredicate(format: "ANY tagIDs = %@", INTagIDInbox) provider.itemSortDescriptors = [NSSortDescriptor(key: "lastMessageDate", ascending: false)] provider.delegate = self self.threadProvider = provider 由于我们已经创建了一个线程供应者,我们就可以使用它的条目数组来存放我们的视图. 供应者不会同步获取结果集, 所以我们需要实现INModelProviderDelegate协议并监听更新. 当新的线程通过以下方式被创建的时候,供应者会调用-providerDataChanged 方法,这些创建新线程的方式包括:1.从缓存从获取 2.通过API加载 3.(某个时间)通过网络数据包被推送到应用. 实现协议确保了我们的应用总是显示最新的数据. 还有其他一些代理方法,比如 providerDataAltered:它让基于UICollection或者UITableView创建邮箱用户界面变得更简单,同时可以使用各种插入删除动画效果.但是目前,我们继续看一些基础的东西. func refreshInterface() { var items = self.threadProvider!.items if items.count == 0 { // display empty state self.subjectLabel.text = "No unread threads!" self.snippetLabel.text = "" self.participantsLabel.text = "" self.dateLabel.text = "" } if let thread = items[0] as? INThread { // display the thread self.subjectLabel.text = thread.subject self.snippetLabel.text = thread.snippet self.dateLabel.text = formatter.stringFromDate(thread.lastMessageDate); .... }}func providerDataChanged(provider: INModelProvider!) { self.refreshInterface()}func provider(provider: INModelProvider!, dataFetchFailed error: NSError!) { self.displayError(error);} 标记为已读在我们的 swift 示例程序中,我们要在用户摇动手机的时候,把当前线程标记为已读,并且显示一个新的线程。用InboxKit,标记为已读是非常简单的。 override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent!) { if (motion == UIEventSubtype.MotionShake) { var items = self.threadProvider!.items if let thread = items[0] as? INThread { thread.markAsRead() } }} 在后台,-markAsReadqueues这个方法使新的API动作进入队列,通过这种行为来从线程中移除未读标签。 INThread对象和本地存储的数据会被立刻更新,但是这个动作将会在手机上排队,直到可以建立连接。如果服务器拒绝这次的动作,那么本地的数据也会回滚。 我们不需要刷新我们的线程供应者-我们的工作已经完成!如果当前线程被标记为已读,那么它就不再需要满足我们线程供应者结果集的标准.供应者会自动匹配它的内容,并且调用providerDataChanged方法,我们实现的代理方法将会刷新我们显示,来展现新集合中的第一个线程。 接下来的步骤 好了! 只用了几十行代码,我们就创建了一个示例程序,它可以从我们的收件箱一条条的获取线程,并且让我们标记为已读.现在它仅仅需要点动画和润色.你可以从这里查看demo的源码:: SwiftEightBall Sample App 我们仅仅接触了InboxKit的一些浅显的东西.在IOS SDK的上层创建我们的swift应用,这意味着我们需要为模型获取本地类的支持,比如线程和通讯录,以及因为支持延时线程和消息动作的SQLite而变得更强大的离线缓存.看看iOS SDK documentation 学习一下更多关于在邮件上层创建美观大方应用的知识.

优秀的个人博客,低调大师

Swift 在对 Objective-C 改进的 6 个方面 【已翻译100%】

在 Atomic Object 的安娜堡办公室,我们做了一个观看2014年的WWDC主题演讲,毫不夸张地说,当Swift宣布的时候,我们感到十分激动。Swift,苹果正在推进的一个更现代的编程语言。我很高兴能获得先机并开始用它开发。 在这篇博文中,我将重点介绍Swift的几个语言特性,这将使开发者的工作更加轻松。 Objective-C语言的问题 当一个开发者申请一个关于Atomic Object的新职位时,我们会给他填写一个(GTKY) Getting To Know You的表。这个表要求填写一些常见的问题,包括技术和其他方面,比如你最喜欢的语言是什么,你会做些什么来改进它?很多开发者的回答不能令人满意,即使开发人员选择objective-C作为他们最喜爱的语言时,也想不出如何改进它!这个回答产生了大量的讨论,让我想起一个Objective-C的问题。仅举几例: 弱类型 - 通常处理id或class,并且需要可怕的C static casts 。 欠佳的枚举语法 - for in已经很好了,但我经常想到一个更好的索引。 缺少操作符重载的类,例如NSNumber的。 所以,我很高兴苹果宣布swift并公开了其语言细节。在这里我会谈一些对Objective-C语言的批评。我强烈建议开发人员下载Swift的书,看一看在Xcode 6的测试版。 激动人心的Swift特性1. 类型推断对我来说这个很有用。无比烦恼的是你不得不将id类型的实例非安全的转化为实际类型,这很容易出错并且向一个实际对象并不相应的id发送信号。总是检查respondsToSelector太乏味了。Swift给我们提供了一个解决方案---var关键字: 1> var anInt = 0 anInt: Int = 0 2> var aDouble = 0.0 aDouble: Double = 0 3> var anotherDouble: Double = 0 anotherDouble: Double = 0 4> var aString = "some string" aString: String = "some string" 注意:就像anotherDouble那种情况,你也可以显示的设置类型。可以用var同样的方式使用let来推断常量的类型。 2. 改进枚举语法 Objective-C有不错的集合枚举语法:**for (SomeType someObject in array) NSLog(@"%@", someObject.whatever);** 这是个不错的语法糖,但是问题是现实编程中,我通常需要一个和集合中元素实例一起的索引变量。. Swift 给了我们许多有用的集合枚举器, 但是尤其令人高兴的是他们提供了一个全局的enumerate()方法,可以用来返回一个包含了数组中元素和索引的元组。 19> array $R2: String[] = size=4 { [0] = "one" [1] = "two" [2] = "three" [3] = "four" } 20> for (index, value) in enumerate(array) { 21. println("Item \(index): \(value)") 22. } Item 0: one Item 1: two Item 2: three Item 3: four 23> 3. Override关键字当在类中声明一个实例函数时,如果他们覆盖了一个基类函数,他们必须标记为override的。如果没有这么做则会得到一个编译时错误。类似的,如果一个标记为override的函数没有覆盖基类的相应函数,同样得到一个编译错误。这一行为将的类更加的清晰和降低运行时崩溃的可能性。 4. 多返回值在我加入Atomic之前的那份工作中,我主要开发C++,并且经常发现自己写一些输出多值的方法。我总是为决定使用引用,pair还是将返回值包装为struct或class来作为参数传递而挣扎不已。 在Swift中,有内置的机制来用一个由任意数量的带标记的数据成员的组成的元组作为多返回值。 46> func calculateStatisticsFromArray(data: Double[]) -> (mean: Double, median: Double, mode: Double) { 47. return (62, 44, 12) 48. } 49> var stats = calculateStatisticsFromArray([]) stats: (mean: Double, median: Double, mode: Double) = { mean = 62 median = 44 mode = 12 } 50> stats.mean $R10: Double = 62 51> stats.median $R11: Double = 44 52> stats.mode $R12: Double = 12 Swift同样支持声明多个变量来显示的获取多返回值: <51> var(mean, median, mode) = calculateStatisticsFromArray(data)** willSet, didSet**在 Swift中, 类具有属性(类似于Objective-C)。有一个声明setter和getter的机制,如果属性的类型是简单的并且需要计算的,但是你想观察他们的变化,两个内置的需要覆盖的方法-willSet和didSet将会有帮助。 1> class Container { 2. var someValue: Double = 0.0 { 3. willSet { 4. println("willSet! \(newValue)") 5. } 6. didSet { 7. println("didSet! \(someValue)") 8. } 9. } 10. } 11> var c = Container() c: Container = { someValue = 0 } 12> c.someValue = 100.0 willSet! 100.0 didSet! 100.0 6. REPL REPL表示“read-evaluate-print-loop”,我认为它是通过沙箱测试输出的代码.您可以输入代码到REPL,如果您在使用一个IDE或者喜爱的文本编辑器,它会被编译/解释和实时运行,并马上能让你看到输出结果。这是开发人员努力学习这门新语言时能看到的一个强大功能。我一直在使用它来学习swift。 使用SWIFT REPL: 1.下载Xcode 6 Beta版。 2.在终端中运行以下命令来切换路径xcrun: sudo xcode-select -switch /Applications/Xcode6-Beta.app/Contents/Developer. 注意:如果要重置,请在使用终端里键入 xcode-select -r 3.xcrun swift 谁将拥有未来?我坚信,在iOS 8和以后的版本中,Swift将成长成为iOS开发的主流语言。尽管如此,苹果已经向我们保证,在运行时将保持二者兼容:我们的Objective-C应用程序仍然可以继续工作。同样清楚的是Swift的语法和语义将改变后的iOS 8。苹果告诉我们,他们不能保证源代码的兼容性,但会提供代码转换器。使用代码转换器的想法让我害怕了一下,我认为迁移到Swift的时间会来得早(iOS的8-9的样子),而不是以后。

优秀的个人博客,低调大师

从 C++ 到 Objective-C 的快速指南 【已翻译100%】

**简介**当我开始为iOS写代码的时候,我意识到,作为一个C++开发者,我必须花费更多的时间来弄清楚Objective-C中怪异的东西。这就是一个帮助C++专家的快速指南,能够使他们快速的掌握Apple的iOS语言。 请注意这绝不是一个完整的指南,但是它让你避免了阅读100页的手册。除此之外,我知道你喜欢我的写作风格。 背景 需要C++的技能,我会比较C++和Objective-C的东西。此外,COM编程也是有用的,因为Objective-C有类似于IUnkown的东西,因此基础的COM编程是有帮助的(但不是必须的) Objective C++是C++和Objective C的组合。你也能使用任何C++的东西混合到Objective C中,但是记住重新命名你的文件从.m到.mm 铛 - 铛! 我们马上就开始我们的教程. 首先我会介绍 Objective-C 的东西,然后是C++中与它对等的东西. 成员函数 // Objective-C - (int) foo : (int) a : (char) b {} + (int) foo : (int) a : (char) b {} // C++ int foo(int a,char b) {} static int foo(int a,char b) {} // Objective-C - (void) foo2 val1:(int) a; // named argument // call [obj foo2 val1:5]; // merely helper: You remember that 5 is assigned to param name val1. 表示的是一个一般的成员函数(通过一个对象实体访问), 而 + 则表示一个静态成员函数, 不需要使用实体就能访问. 当然,像C++, 静态成员不能访问实体变量. 此外,Objective-C函数函数可以有赋予了名称的参数,这样让什么参数获得什么值会更一目了然. 理论上,被赋予了名称的参数允许程序员按任何顺序传入参数,但是Objective-C却规定要按声明的顺序传参. 通过一个指针或者一个静态成员调用一个成员 // Objective-C NSObject* ptr = ...; // some pointer [ptr foo:5:3]; // call foo member with arguments 5 and 3 [NSObject staticfoo:5:3]; // call static function of NSOBject with arguments 4 and 3 // C++ CPPObject* ptr = ...; // some pointer ptr->foo(5,3); CPPObject::staticfoo(5,3); Objective-C 使用 [ ] 来调用成员函数并传入用:分割开的参数, 其对于ObjectiveC中ptr为nil的情况非常友好,在这种情况下“调用”将会被忽略掉(而在C++中,这种情况会抛出一个指针冲突异常 ). 这使得消除对nil对象的检查成为可能. 协议VS接口 // Objective-C @protocol foo - (void) somefunction; @end @interface c1 : NSObject<foo> @end @implementation c1 - (void) somefunction { ... } @end // C++ class foo { virtual void somefunction() = 0; }; class c1 : public NSObject, public foo { void somefunction() { ... } } 协议= 抽象类. Objective-C 和 C++ 之间的区别在于,在 Objective-C 中, 函数并不是必须要被实现的. 你可以让一个可选的方法被动的被声明,而这仅仅只是向编译器发出暗示而已,并不是编译必须的. 检查一个方法是否被实现了 // Objective-C NSObject* ptr = ...; // some pointer [ptr somefunction:5:3]; // NSObject 不必一定为其编译而实现somefunction. 如果没有被实现的话,会引发异常. // C++ CPPObject* ptr = ...; // some pointer ptr->somefunction(5,3); // CPPObject 必须实现 somefunction() 否则程序根本就不会被编译. Objective-C 成员函数就是(Smalltalk中的) "消息" 而在Objective-C中时,我们则说接收者 (即指针) 会向一个选择器做出回应, 这意味着其实现了我们尝试去调用的虚函数. 当有一个接口是, C++ 对象必须实现其所有的成员函数. 而在 Objective-C 中这并不是必须的,因此我们可以向并不必须要实现它的某个地方发送一个”消息“ (如此就会引发一个异常). // Objective-C NSObject* ptr = ...; // some pointer if ([ptr respondsToSelector:@selector(somefunction::)] [ptr somefunction:5:3]; 现在我们就可以确定接收者向选择器做出回应, 我们因此就可以调用它了. 在 C++ 中不需要这样的检查, 因为实现必须常常”向选择器做出回应“, 否则源代码根本就不会被编译. 请注意我们必须知道选择器获取了多少个参数(因此在该@selector中是2个 ::s 向下转型 // Objective-C NSObject* ptr = ...; // some pointer if ([ptr isKindOfClass:[foo class]] [ptr somefunction:5:3]; // C++ CPPObject* ptr = ...; // some pointer foo* f = dynamic_cast<foo*>(ptr); if (f) f->somefunction(5,3); 现在只有使用NSObject的"isKindOfClass"助手——所有Object-C类的基础,才能像在C++中那样向下转型. 符合协议? // Objective-C NSObject* ptr = ...; // some pointer if ([ptr conformsToProtocol:@protocol(foo)] [ptr somefunction:5:3]; // C++ CPPObject* ptr = ...; // 某个也继承自foo的指针 foo* f = ptr; // 或者编译器会警告我们说ptr不能同foo兼容. f->somefunction(5,3); 现在我们要检查接收器是否 符合一个协议 (或者说,在C++就是实现一个接口), 以便我们可以发送这个协议包含的消息. 嘿嘿,它像极了Java的类和接口,而在C++中,完全被实现的类和一个“接口”之间没有技术上的差别. void* 、 id 或者 SEL? // Objective-C id ptr = ...; // some pointer if ([ptr conformsToProtocol:@protocol(foo)] [ptr somefunction:5:3]; SEL s = @selector(foo:); // a pointer to a function foo that takes 1 parameter // C++ void* ptr = ...; // some pointer foo* f = dynamic_cast<foo*>(ptr); if (f) f->somefunction(5,3); id 是通用的用于Objective-C类的类似于 void 的东西. 你只能使用id而不是 void 因为id可以通过ARC(稍后会详细介绍到它)编程一个可被管理的指针,而因此编译器需要在元指针类型和Objective-C指针之间做出区分. SEL 是一个用于选择器(C++函数指针)的通用类型,而你一般可以通过使用关键字@selector带上函数名字和:::::s的一个数字来创建一个选择器, 这取决于可以传入多少参数. 选择器实际上就是一个字符串,它会在运行时绑定到一个方法识别器. 类定义,方法,数据,继承 // Objective C @class f2; // forward declaration @interface f1 : NSOBject // Objective-C supports only public and single inheritance { int test; // default = protected @public int a; int b; f2* f; } - (void) foo; @end @implementation f1 - (void) foo { a = 5; // ok self->a = 5; // ok super.foo(); // parent call } @end // C++ class f1 : public CPPObject { int test; // default = private public: class f2* f; // forward declaration int a; int b; void foo(); } void f1 :: foo() { a = 5; // ok this->a = 5; // ok CPPOBject::foo(); // parent call } Objective-C中的实现范围在@implementation/@end 标记 (在 C++ 中我们可以将实现放在任何带有::范围操作符的地方)之中. 它使用@class关键字用于事先声明. Objective-C 默认带有 私有(private) 保护, 但仅用于数据成员(方法必须是公共的). Objective-C 使用 self 而不是 this ,并且它还可以通过super关键字调用它的父类. 构造器和析构器 // Objective-C NSObject* s = [NSObject alloc] init]; // can return nil if construction failed [s retain]; // Increment the ref count // C++ CPPObject* ptr = new CPPObject(); // can throw ptr->AddRef(); // Objective-C NSObject* s = [NSObject alloc] initwitharg:4]; [s release]; // C++ CPPOBject* ptr = new CPPOBject(4); ptr->Release(); Objective-C中的内存分配是通过静态成员方法alloc来实现的,所有 (做为NSObject后裔)的对象都有这个方法. self 在Objective-C中是可以被赋值的,而如果构建失败的话它就会设置成nil(而在C++中则会被抛出一个异常). 内存分配之后实际被构造器调用的是一个公共的成员函数,在Objective-C中默认的是init方法. Objective-C 使用同COM益阳的引用计数方法, 而它也使用 retain 和 release (等同于IUnknown的 AddRef() 和 Release() 方法). 当引用计数到了0,则对象会从内存中被移除掉. 多线程 // Objective C @interface f1 : NSOBject // Objective-C supports only public and single inheritance { } - (void) foo; - (void) threadfunc :(NSInteger*) param; - (void) mt; @end @implementation f1 - (void) threadfunc : (NSInteger*) param { [self performSelectorOnMainThread: @selector(mt)]; } - (void) mt { } - (void) foo { [self performSelectorInBackground: @selector(thradfunc:) withObject:1 waitUntilDone:false]; <div></div>} @end Objective-C 有一些针对NSObject的内建功能,可以在另外一个线程中操作一个选择器 (== 调用一个成员), 在主线程中,等待一次调用等等 . 在NSObject 参见更多信息. 内存和ARC // Objective-C @interface f1 : NSObject { } @property (weak) NSAnotherObject* f2; // 当没有其它强引用存在的时候,它将会被自动设置成. @end - (void) foo { NSObject* s = [NSObject alloc] init]; // 如果构造失败的话会返回nil // use s // end. Hooraah! Compiler will automatically call [s release] for us! } 这里需要你忘记自己良好的 C++ 习惯. OK Objective-C 使用了一个垃圾收集机制,这种东西我们C++很讨厌,因为它很慢并会让我们想到Java. 但是 ARC (自动进行引用计算) 是一种 编译时间 特性,它会告诉编译器 "这里是我的对象:请帮我算算啥时候它们才要被销毁吧". 使用ARC你就不需要发送 retain/release 消息给你的对象了; 编译器会自动帮你代劳的. 为了能帮助编译器决定保留一个对象多长时间,你还要一个弱引用指向一个变量. 默认的,所有的变量都是强引用(==只要强引用还存在,被引用的对象就会存在下去) . 你也可以获取一个弱引用,它会随着每个强引用消失而失去它的值. 这在类成员从XCode的Builder Interface(像RC 编辑器)处获取它们的值时,会很有用,当类被销毁时,那些成员也会失去它们的值. Strings // Objective-C NSString* s1 = @"hello"; NSString* s2 = [NSString stringWithUTF8String:"A C String"]; sprintf(buff,"%s hello to %@","there",s2); const char* s3 = [s2 UTF8String]; NSString 是一个Objective-C字符串的不可变表示. 你可以使用其一个静态方法,或者是一个带有@前缀的字符串文本来创建NSString. 你也可以使用 %@ 来向printf家族函数来表示一个NSString, 数组 // Objective-C NSArray* a1 = [NSArray alloc] initWithObjects: @"hello",@"there",nil]; NSString* first = [a1 objectAtIndex:0]; NSArray和NSMutableArray是在Objective-C中处理数组的 两个类(两者的差异是,NSArray元素构造时必须通过构造函数,而NSMutableArray可以在之后更改)。典型构造函数的生效,你必须通过nil去作为“结尾元素”。排序/搜索/插入函数对于NSArray和NSMutableArray来说是一样的,在第一行中的例子它返回一个新的NSArray,而在NSMutableArray的例子里,它修改的是一个存在的对象。 分类 // C++ class MyString : public string { public: void printmystring() { printf("%s",c_str()); } }; // Objective-C @interface MyString (NSString) - (void) printmystring; @end @implementation MyString (NSString) - (void) printmystring { printf("%@",self); } @end // C++ MyString s1 = "hi"; s1.printmystring(); // ok string s2 = "hello"; s2.printmystring(); // error, we must change s2 from string to MyString // Objective-C NSString* s2 = @"hello"; [s2 printmystring]; // valid. We extended NSString without changing types.C++依赖 继承机制来实现一个已知的类。这是很麻烦的,因为所有用户的实现类必须使用另外的类型名称(在例子中,MyString用来代替string)。Object-C通过使用 分类(Categories)允许扩展一个已知的类内 同型(same type )。上面链接中所有源代码在extension.h文件 (具有代表性的是像NSString+MyString.h这样的)中可以查看,上面例子中,我们立即就有可以调用新的成员函数,而不需要改变NSString类型为MyString。 块 和 Lambda // Objective-C // member function -(void)addButtonWithTitle:(NSString*)title block:(void(^)(AlertView*, NSInteger))block; // call [object addButtonWithTitle:@"hello" block:[^(AlertView* a, NSInteger i){/*DO SOMETHING*/}]; 块 是Objective-C 用来模拟lambda功能的一种方式. 查看Apple的文档,从AlertView的示例 (使用块的UIAlertView)可以获得更多有关块的技术. C++ 开发者使用 Objective-C 和 ARC 的重要提示 // C++ class A { public: NSObject* s; A(); }; A :: A() { s = 0; // 可能会奔溃,这是常发生在发布模式下! } 你已经知道给所有的顾客都打两折对你而言有多痛苦了,因为你bug重重的软件会在发布模式下奔溃,而在调试模式下总是妥妥的. 没有用户会理解程序员,是不是? 让我们来看看这里发生了什么. s = 0 这一行将 0 赋值给了一个变量,而因此不管这个变量之前取值是什么,首先都会被释放掉,所以编译器在赋值之前执行了一次 [s release] . 如果 s 之前已经是 0 了,假设是在调试构建的话,不会发生任何不好的事情; 如果 s 是一个nil的话,使用[s release] 是再好也不过的. 然而,在发布模式下, s可能是一个野指针,所以它可能在被“初始化”为0之前包含任何值(这很危险是不是?) .在C++中,这并不是一个问题,因为它里面是不存在ARC的. 而在Objective-C中编译器并没有办法了解这是一次"赋值" 还是一次 "初始化" (如果是后者,它就不会发送发布消息). 下面是正确的方式: // C++ class A { public: NSObject* s; A(); }; A :: A() :s(0) // 现在编译器就知道确定 it&apos;s 是一次初始化了, 一次就不存在 [s release] { } 现在编译器就不会去尝试调用一个 [s release] 因为它知道它是这个对象的第一次初始化. 请小心! 从Objective-C 对象到 C++ 类型的转换 // Objective-C NSObject* a = ...; void* b = (__bridge void*)a; // 你必须在Objective-C和C类型支架使用 __bridge void* c = (__bridge_retained void*)a; // 现在是一个+1的保留计数,而你必须在稍后释放这个对象 NSObject* d = (__bridge_transfer NSObject*)c; // 现在ARC取得了对象c的”拥有权“, 将其装换成一个ARC管理的NSObject. 我可以分析这一切,而我的建议是简单的. 不要 将ARC类型和非ARC类型混在一起. 如果你必须转换一些Objective-C对象的话,使用id而不是void*. 否则,你将会遇到严重的内存故障.

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册