如何制作只能在库中看到的目标 c 方法,而不是在导出的标头中
Posted
技术标签:
【中文标题】如何制作只能在库中看到的目标 c 方法,而不是在导出的标头中【英文标题】:How can I make an objective c method that can only be seen within a library, not in exported headers 【发布时间】:2012-11-06 19:56:09 【问题描述】:我正在构建一个用于控制 ios 外部附件的静态库。作为其中的一部分,我想展示一组最小的公共头文件,以与编译的库一起分发。
我有一个需要公开的类,但我想在它上面创建一些框架私有方法。我为其中一个公共类创建了一个类别来添加私有方法,包括一个初始化程序。这适用于项目测试,但会生成 -[MyClass initMethodDefinedInCategory:]: unrecognized selector sent to instance 错误。
类别标题:
#import "MyClass.h"
@interface MyClass (LibraryPrivateMethods)
- (id)initMethod:(NSData *)data;
- (int)someOtherMethod:(NSData *)data;
@end
使用类
#import "MyOtherClass.h"
#import "MyClass.h"
#import "MyClass+LibraryPrivateMethods.h"
@implementation MyOtherClass
#pragma mark - Instance Methods
- (id)initWithData:(NSData *)data
self = [super init];
if(self)
MyClass *mc = [[MyClass alloc] initMethod:data]; // errors here
_property = mc;
return self;
我已尝试按照this Apple tech note 中的建议添加-ObjC
链接器标志。我还尝试按照this SO answer 中的建议添加-all_load
标志。
编辑:意识到我只是在 XCode 构建中添加,忘记检查构建脚本,如下所示。
set -ex
INSTALL_PATH=$WORKSPACE/artifacts
[ -z $INSTALL_PATH ] || INSTALL_PATH=$PWD/artifacts
rm -rf $INSTALL_PATH
mkdir -p $INSTALL_PATH
PROJ=$SRCROOT/MyLib.xcodeproj
xcodebuild -project $PROJ -sdk iphoneos INSTALL_ROOT=$INSTALL_PATH/device install
xcodebuild -project $PROJ -sdk iphonesimulator INSTALL_ROOT=$INSTALL_PATH/simulator install
lipo -create -output $INSTALL_PATH/libMyLib.a $INSTALL_PATH/device/libMyLib.a $INSTALL_PATH/simulator/libMyLib.a
mv $INSTALL_PATH/device/Headers $INSTALL_PATH
rm -rf $INSTALL_PATH/device $INSTALL_PATH/simulator
# create zip for distribution.
(cd $INSTALL_PATH; zip -r ../MyLib-release.zip libMyLib.a Headers ../documentation/LibraryDocs/html ../documentation/LibraryDocs/docset)
我应该在哪里将 -ObjC 标志添加到构建脚本?
你有什么理由不能在一个类别中有一个初始化方法吗?正如this Apple doc 所说,这似乎是可能的
类别方法可以做任何在类中定义的方法 适当的可以做。在运行时,没有区别。方法 添加到类的类别被所有类的继承 子类,就像其他方法一样。
然后我尝试使用类扩展,但我不确定如何使该方法仅对框架类可见。
@interface MyClass ()
- (id)initMethod;
@end
如果我随后从库中的另一个类调用 [[MyClass alloc] initMethod]
,我会收到“MyClass 的无可见 @interface 声明选择器 initMethod”错误。
如何使对象上的方法只能被框架中的其他类访问,而不是在 MyClass.h 中导出?
【问题讨论】:
这很奇怪——我以前也遇到过这个问题,添加-ObjC
链接器标志解决了我的问题。在创建静态库和链接最终可执行文件时,您是否尝试将 -ObjC
标志传递给两个链接器命令行?
你的initMethodDefinedInCategory:
方法的实现在哪里?它与公共方法在同一个 .m 中,还是在单独的 .m 文件中?
@Darren 实现在 MyClass+LibraryPrivateMethods.m 文件中。所以一个单独的文件到公共方法。
@AdamRosenfield 你可能正在做某事。我忘记了构建脚本。将其添加到问题中。我将在构建脚本中的哪里传递 -ObjC 标志?还是 XCode 会自动做这种事情?
@aj.esler:如果您使用xcodebuild
来构建静态库,那么您不会在命令行上传递任何内容——您可以在某处添加-ObjC
标志项目设置。如果没有明确的设置,应该在某处有一个“附加命令行选项”字段(或类似的东西)。
【参考方案1】:
将类别声明放在单独的 .h 文件中。将此私有 .h 文件导入框架中需要访问类别方法的任何 .m 文件中。不要将此 .h 文件打包到分发给客户使用的公共 .h 文件集中。
顺便说一句 = 不要使用类扩展,使用命名类别。
【讨论】:
这正是我所做的。我已更新我的问题以更好地显示问题。【参考方案2】:见the Apple Tech note底部的说明:
重要提示:对于 64 位和 iPhone OS 应用程序,存在阻止 -ObjC 从仅包含类别且不包含类的静态库加载对象文件的链接器错误。解决方法是使用 -all_load 或 -force_load 标志。
由于MyClass+LibraryPrivateMethods.m
仅包含类别代码,听起来您看到了注释中描述的错误。
将您的私有实现移至主 MyClass.m 或尝试使用 -all_load
或 -force_load
标志。
【讨论】:
我对此的解释是我很好,因为图书馆既有类又有类别。总共有大约十几个班级,一个类别。 该注释与单个对象文件有关。 MyClass+LibraryPrivateMethods.m 将编译为不包含任何类的单个目标文件。该错误会阻止链接器正确处理该目标文件。【参考方案3】:无法在为该问题分配的时间内解决此问题。我最终删除了该类别并将初始化程序代码移动到 MyOtherClass initWithData 方法中。 这编译得很好并且可以工作。
【讨论】:
以上是关于如何制作只能在库中看到的目标 c 方法,而不是在导出的标头中的主要内容,如果未能解决你的问题,请参考以下文章
我有一个Xcode静态库项目,如何添加测试目标,以便我可以在那里运行它? (而不是在链接到它的项目中。)