小弟初学objective-c,对于extension的作用一直无法理解,请各位前辈指点一二。

2013-08-31 09:45:05 +08:00
 meta
看到很多书上都说,扩展可以用来实现类的私有实例变量和方法,那么把方法从.h文件中去掉,使其不被引用到,不就实现私有方法了么,为什么要写成扩展的方式呢。
又看到有说如果可以在.h中将属性置为readonly而在.m的扩展中再设置为readwrite,这样就能保证属性对外部是只读的而对内部是读写的,但是只要在.m中写个@synthesize x = _x;不也能达到这样的效果么。

所以对使用扩展到底有什么用处一直搞不明白,请各位赐教。
2016 次点击
所在节点    C
28 条回复
ichord
2013-08-31 17:05:07 +08:00
@meta 在实现的效果上我也完全找不到有什么区别了. 我也求解答!
书上和网上的例子能看出的却别也就是用法概念之类的问题..

https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html#//apple_ref/doc/uid/TP40011210-CH6-SW6

看这个官方的例子, 实际实现效果的区别也就是只有类内部可以使用 `[self setProperty:xxx]` 或者 `self.property = xxx` 这样的用法而已.

----

* 在 @interface 声明的 instance variable 是 protected 的.
* 在 @implement 声明的 instance variable 是 "private" 的.
* @synthesize 自动声明的 instance variable 也是 "private" 的.
* objective-c 里面的类方法只有两种:
** 在 @interface 声明的. "public"
** 没在 @interface 声明的. "private". (其实是没有这个概念的是吧?!)

所以要声明 instance variable 或者 method 为私有的(private) 的话, 根本没必要在 class extension 的声明.

----

我在 <Learning Cocoa with Objective-c> 的 `Class Extensions` 章节看到这两句话:

>
there are two reasons for extending a class:
1. You want to add extra behavior and logic to an existing class
2. You want to break up one of your own classes into separate components.


我现在能想到的就是

1. 配合 `category` 将一个大类进行各种拆分组合, 类似于 `Mixin` 的用法.
因为 `category` 可以创建方法但不能创建类变量, 而另一个则可以创建类变量但不能创建方法. 而且方法声明貌似没什么用处...

2. 将一个大类以不同的 @interface 组合暴露出去, 按适用需要 `import` (这个貌似也很弱的样子... = =)

= =. 今天就先到这好了... 以后遇到再说...
ichord
2013-08-31 17:07:13 +08:00
@chchwy cool.
xuzhe
2013-08-31 19:12:43 +08:00
首先,

_x = a;



self.x = a;

的区别你理解了吗?

这个能理解的话,你的问题应该自己也能想明白了。
walkingway
2013-08-31 19:58:20 +08:00
你举的两个例子:
第一个 1和2 没有什么区别,只要不在.h里的方法默认都是私有方法

第二个 你真正理解为什么要用 @synthesize x = _x 而不是 @synthesize x么?
这么做的目的是为了方便区分属性x和实例变量_x而已,仅此而已。
你在.h里声明x了只读,在.m的扩展里不改写为读写的话,是无法用self.x=...来赋值的。当然你说你直接用_x=...来赋值可以,但是,这么做也就跳过了getter和setter方法,当然不受readonly的限制。
如果你getter和setter方法里做点特别的事情,你用_x就没法和self.x达到一样的效果了。

不知道说明白没
walkingway
2013-08-31 20:07:03 +08:00
简单说就是 self.x 和 self.x = ... 调用的是@property 生成的getter和setter方法,
@synthesize x = _x 生成一个实例变量,为了不和属性x混淆改名为_x,以后你写_x就是直接访问的实例变量,不会调用getter和setter方法。你getter和setter方法里做的一些额外事情,也无法实现。
xsown
2013-09-01 01:15:12 +08:00
1) 用 extension 的方式在 .m 文件里把一个 property 从 readonly 改为 readwrite,改变的是这个 property 本身,这时候你就可以写 self.someProperty = xxx 而不会引起编译器报错。

2) 如果你把这个 property 给手动 synthesize 到某个 ivar 上,然后修改 ivar 的值,表面上看确实与 readwrite 的效果等同。但是 property 上面的修饰词可能会造成一些区别,比如 atomic,那么当你写 self.someProperty = xxx 时,编译器实现的代码会是类似 someLockFunction(); _someProperty = xxx; someUnlockFunction(); 这样的形式,确保不同的线程同时访问这个 property 时不会出错。

3) property 作为一种封装,getter 和 setter 有很大的自由度可以实现复杂的行为。而对 ivar 的读写仅仅是取值/赋值。所以 readwrite 化的 property 更加灵活。
meta
2013-09-01 09:42:07 +08:00
非常感谢楼上各位,@chchwy 完全解决了我的疑惑,@walkingway 和@xsown 的解答也很有价值。我不是不了解属性和实例变量的区别,我疑惑的是使用场景,因为私有的属性和公有的属性使用场景是完全不一样,我不明白在什么场景需要用到私有的属性而不使用变量,固然可以简单的用self.x访问到自定义的getter和setter方法,但是这样比直接使用setX也简单不到哪里去。@xsowm说的线程安全的问题很有道理,但我认为既然是私有变量,不需像对外的接口一样需要形式上的一致,那么处理方法多种多样,没看出来一定要使用extension的理由。所以@chchwy 兄的介绍就让我完全明白了。

这次真是获益匪浅,非常感谢大家。
xuzhe
2013-09-01 10:11:02 +08:00
很明显 chchwy 同学也没完全搞明白,他的第3点总结是不对的。
楼上几位都说得那么清楚了,可 @meta 同学还是总结出“没看出来一定要使用extension的理由“,好吧。
vixvix
2013-09-01 12:11:46 +08:00
extension跟category的区别是可以加ivar和properties. 这个特别属性使得在interface决定的情况下,不许要做大的修改你也可以给这个interface添加需要的功能。
在大型项目或者外包项目中,interface在项目组或者公司间定下后通常就很少修改,这时你要扩展功能用extension就可以很容易的添加ivar或者properties。你或者可以使用外部singleton,但可读性和可维护性相对与extention就会差很多。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/80831

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX