为什么何时以及如何开源iOS组件

我们都为不同的iOS项目做一些特定的UI控件,有时甚至看到可以在其他项目或将来的项目中重复使用的部分。 这是一个很好的机会,可以为我们节省一些时间,并学到新的东西并变得更好。

本文基于我以前发布的iOS控件CircleProgressBar的经验,它在GitHub上有350颗星,安装了2k多个独特的应用程序,下载了254k多个下载,并且此控件仍按预期运行。 我相信这是由于我在将控件公开之前做出的初步决定以及不定期的支持和存储库管理。

为什么要开源?

我确实相信开放源代码,我们所有人都看到许多强大的图书馆和背后的强大社区。 我们大多数人每天都使用许多此类库,例如AFNetworking / Alamofire或SDWebImage。 无需实施自己的解决方案(即使它是“轻量级”的),然后在每次您需要支持新协议或功能(例如缓存)时对其进行扩展,则可以更有效地利用成千上万其他开发人员使用和现场测试的现有库。

但是除了这个伟大的事业之外,我只是想分享自己的代码,我认为这是一次很棒的新体验,一次新的冒险。 我的控制很简单,我认为没有什么可以解决的,不能改善。 我想:“我会把它放出来等待。” 但是我对获得的成果和所学到的东西感到非常惊讶!

这就是为什么我鼓励您自己尝试一下的原因,因为起初很难理解我们可以从中得到什么,但是只有当您开始给予您更多的响应时,您才可以尝试。

何时开放源代码?

我们创建的某些内容并不意味着要共享或很难共享。 我相信您应该问要共享的组件的第一个问题: 为什么有人要使用它? 就像SOLID原则中S代表“单一职责原则”一样,最好是您的库仅解决一个主要问题:处理http请求,管理ftp连接,显示日期选择器等。

像许多Utils库这样的多功能库通常不经常使用,因为大多数开发人员只需要使用“一个字符串操作”,该操作比添加其他依赖项更容易复制粘贴。 只需向任何前端开发人员询问有关JQuery的信息,以及他们如何喜欢它。 尽管它在某些具有特定元素查询的繁重项目中可能非常有用-一些开发人员非常懒惰,以至于他们将其添加为对微型项目的依赖,但是当他们需要的只是简单的getElementById函数时, getElementById可用纯JavaScript。

另外,使您的库尽可能独立也是非常重要的,因为您拥有的依赖关系越多–每次主要iOS版本更新后,人们希望依靠您的库并花费大量时间修复所有内容的人就越少。

当您最终决定要对代码的某些部分进行开源时,无论是控件还是库,都一定要准备一些额外的时间,以便为类和代码最终确定和准备清晰的接口。

如何开源?

现在我们到了最有趣的地方-终于做到了。

依存关系

尽可能删除所有依赖项。 与遵循一系列依赖关系来修复某些问题然后再次更新您的存储库以更新所需的依赖关系版本相比,某些问题更容易在您的存储库中内联修复。

我见过很多次,当某些控件依赖十六进制颜色库获取2-3个默认颜色常量时。 如果使用它来定义常量值,那么具有这种依赖性是没有意义的。 只需将其替换为简单的UIColor(R:G:B:A:)调用即可描述相同的颜色。

为了控制自己,我决定避免任何依赖关系,并且在主要的iOS版本中,我不需要进行任何更新。 该控件只是按预期工作。 因此,除非确实有必要-删除依赖项,并使控件尽可能独立。

我还看到了依赖于某些特定架构(例如MVVM)的不同控件。 控件的创建者在他的项目中使用MVVM或VIPER真的很酷,但是尝试考虑标准的Apple控件库,他们会强迫您使用其MVC吗? 您可以将任何标准的Apple Control与任何体系结构一起使用,那么为什么要为您的控件添加这种依赖关系并减小库的可能客户端的范围呢?

类接口

要为您的库或控件中的类创建一个清晰的界面,请尝试将其视为一个新用户,只希望解决您的控件正在解决的问题。 尝试以这个新来的新用户接触您的图书馆,这个新用户对您需要解决的所有问题一无所知。 尝试考虑什么是最适合此类用户的界面,它将阻止他进入您的代码来学习什么以及为什么。

这可能是一个非常有创意的步骤,我可能无法提供太多有关此信息,而不是分享我的经验。

在我的库CircleProgressBar中,我只想拥有一个进度条,而不是水平填充条可以以圆形方式围绕中心移动。 我假设用户期望可以使用一些熟悉的界面,所以我决定将标准UIProgressView用作类界面的基础。 我实现了相同的方法setProgress:animated:和只读属性progress 。 这里的想法是,您可以简单地用UIProgressView替换InterfaceBuilder中的现有UIProgressView ,而无需更改使用它来更新进度或检查状态的任何代码。

客制化

当您的控件解决了开发人员的问题时,并不需要与每个UI / UX设计人员的愿景保持一致。 因此,屏幕上看到的每个元素用户(开发人员)都是变化的主题。

最简单的方法就是提供一种更改控件中使用的每种颜色,字体和其他元素的方法,就我而言,有以下定制属性:

  //进度条定制 
@property(非原子)CGFloat progressBarWidth;
@property(非原子)UIColor * progressBarProgressColor;
@property(非原子)UIColor * progressBarTrackColor;
@property(nonatomic)CGFloat startAngle;

//提示视图自定义(在进度栏中)
@property(nonatomic)BOOL hintHidden;
@property(非原子)CGFloat hintViewSpacing;
@property(非原子)UIColor * hintViewBackgroundColor;
@property(非原子)UIFont * hintTextFont;
@property(非原子)UIColor * hintTextColor;

但是,有时这还不够,您不应忘记使用自己的创造性思维。

就我而言,我为所有元素提供了自定义功能,但仍从我的用户那里学习了新的用例。 例如,在我的控件中,进度条的中心有一个HintView,用户可以根据进度参数定义要在其中写入的文本。 我决定为用户提供特殊的StringGenerationBlock ,它接受float progress并返回NSString*以便用户可以根据进度定义要显示的文本。 看起来已经足够了,但是后来我对NSAttributedString*支持有了功能请求。 最初提供它看起来很自然,但我什至没有考虑过这种情况。 您的用户确实可以帮助您改进界面,提供新的用例。

支持与社区

对于我而言,这已成为最有价值的部分,但是仅在最初释放此控件的几个月后。 起初,由于我的自我,我要共享此控件,我只是想发布此控件,以便其他人使用它并使我对此感到满意。 但是只有当我开始奉献时,我才最终感觉到我也开始接受自己的东西,远远超过了我所给予的。 在您的控件/库周围建立的支持和社区可以帮助您发现实现中的问题,为您提供第二意见或新的外观,并最终从中学习以变得更好。

首先,您的用户可以帮助您解决代码中的问题并发现一些错误的逻辑。 例如,我没有尝试使用具有透明背景的控件-但我的一位用户报告说存在错误。 因为这听起来像是UI控件所期望的标准行为,所以我将其修复。

另一个用户报告说,当您非常频繁地更新进度时,例如在文件上传过程中的某个进度更新块中,它无法及时执行(更新进度的调用频率比更新动画的持续时间要高)。 甚至这是非常值得支持的东西-在这种情况下,我还没有对其进行大量测试。

除了修复程序外,另一个重要的事情是新功能和用例。 那才是真正使您的控件/库更好的东西。

在我的案例中,GitHub用户@hildert提交了第一笔PR贡献,并进行了更改,这些更改允许设置自定义startAngle来绘制进度。 那是我最初不知道的,但是用户希望可以控制。 在对代码样式进行了一些更改之后,它被批准并合并了。令我感到很惊讶的是,我第一次不需要自己做,而且这确实使控制变得更好。

但是,并非所有PR都应被接受并合并。您仍应保护最初的想法,使其免受不适合的更改的影响。 我还有其他需要拒绝的贡献,因为这与我对UI控件的想法不符。 贡献者希望添加其他事件以监视控件状态何时更改,以在每次更新绘制后调用特定的块。 但是,由于仅对呈现数据进行了此控件,因此基于控件呈现数据的方式构建应用程序逻辑的想法并不符合我的最初假设。 用户在调用setProgress:animated:之前在其模型/控制器中具有所有必需的数据,并且应围绕其拥有的数据构建其应用程序逻辑,而不是依赖于仅用于显示事物的UI控件。

最后的想法

我的想法是创建一个易于集成,易于使用和易于自定义的控件。 很清楚,这样的小型库无法成长为许多开发人员每天都会使用的大型必需库。 大型图书馆周围的大型社区将需要更多的捐款管理以及与参与者有关图书馆愿景的讨论。

但我确实相信,如果会有更多好的独立小组件同时解决一个问题,那么我们可以更快,更轻松地构建应用程序。 因此,我鼓励您自己尝试并获得宝贵的经验,这将改变您的思维方式。

谢谢阅读! 我希望您觉得它有用或至少可以给您一些新鲜的想法。 力求简明扼要,但是如果您想要一些更具体的示例和/或有建议,请在下面的评论中让我知道!