【问题标题】:Prevent instantiation of readonly objects from framework防止从框架实例化只读对象
【发布时间】:2013-03-03 03:37:26
【问题描述】:

我目前正在为 iOS 创建一个客观的 c 框架,以帮助促进 API 和开发人员之间的交互。作为其中的一部分,我返回了各种只读对象数组,开发人员可以使用这些数组向用户显示信息。但是,我想确保向用户显示的对象仅来自框架,并且不能由使用框架的开发人员实例化。

我当前的实现使用了一个自定义的 constructor 初始化器,它从 api 获取 JSON 来实例化自己。我知道访问我的自定义 constructor 初始化程序的唯一方法是将其定义放在头文件中,这样不仅我自己可以访问它,开发人员也可以访问它。我知道当用户尝试使用默认的 constructor 初始化程序 -(id)init; 时,我可能会引发不一致异常,但我无法阻止他们创建自己的 JSON 字符串并调用我的自定义 构造函数初始化器。

我是否采取了正确的方法来保护我的私有框架免受使用它的开发人员的干扰?我还能如何解决这个问题以确保这些对象中数据的有效性?

来源:Is it possible to make the -init method private in Objective-C?

【问题讨论】:

  • 这似乎有点像一场失败的战斗。正如您所读到的,实际上没有办法阻止其他类在您的对象上调用某个方法。为什么除了你之外没有一个类被实例化如此重要?作为一种极端措施,如果您从 Web 服务获取数据,您可以在服务器端对 JSON 进行加密签名,并在使用框架内的对象之前检查签名。但这似乎有点像XY Problem
  • 取决于我们最终是否会遇到开发人员尝试绕过我们的框架的问题,这可能是我们将来考虑使用的路线。感谢您的建议。

标签: objective-c frameworks constructor instantiation data-protection


【解决方案1】:

您是正确的,由于其动态调度系统,Objective-C 本质上不允许真正的私有方法。但是,假设您的问题不是关于真正的安全性,而只是让您难以以不正确的方式使用该框架,那么您有几个选择。

一个简单而常见的解决方案是将您不想公开公开的方法的声明放在单独的头文件中的一个类别中。您仍然可以将这些方法的实现放在类的主实现文件中。所以,一个像这样的标题:

// MyClass+Private.h
@interface MyClass (Private)
- (void)aPrivateMethod;
@end

然后,在您需要访问这些私有方法的您自己的源文件中,您只需导入 MyClass+Private.h。

对于框架,您可以将每个头文件设置为 Public 或 Private。私有标头不会被复制到框架包中,因此对框架用户不可见。为此,您可以在 Xcode 中打开“实用工具”窗格(右侧滑出窗格),选择相关标题,然后在“目标成员资格”下相关行的第二列中选择“私有”。

【讨论】:

  • 这就是我要找的。由于无法防止直接调用方法,隐藏构造函数似乎是我能做的最好的事情。这当然与我想要完成的目标一致。感谢您的帮助!
  • @Krejko Objective-C 没有构造函数;它有分配方法和初始化器。固然迂腐,但有助于准确地描述事物。
  • @bbum 注意到了。我一直在 Android 和 iOS 之间徘徊,我开始混合我的术语。
【解决方案2】:

基于 Andrew Madsen 的解决方案,我最终使用的是为每个对象设置两个不同的头文件;一种是公开的,一种是私人的。公共标头仅包含开发人员访问只读属性所需的信息。然后我的私有标头导入公共标头,还包含一个类别,其中包含我需要在 SDK 中使用的所有方法调用(包括初始化程序)。然后我将私有标头导入到我的实现中。结构如下:

公共头文件 MyObject.h

#import <Foundation/Foundation.h>

@interface MyObject : NSObject
    @property (nonatomic, retain, readonly) NSString *myValue;
@end

私有头文件 MyObject+Private.h

#import "MyObject.h"
@interface MyObject (Private)
    +(MyObject*)MyObjectFromJSONString:(NSString*)JSONString;
    -(id)initWithJSON:JSONString:(NSString*)JSONString
@end

私有实现 MyObject.m

#import "MyObject+Private.h"
@implementation MyObject

@synthesize myValue = _myValue; //_myValue allows local access to readonly variable

- (id)init {
    @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"-init is not a valid initializer for the class MyObject" userInfo:nil];
    return nil;
}


+(MyObject*)MyObjectFromJSONString:(NSString*)JSONString;
{
    return [[MyObject alloc]initWithJSON:JSONString];
}


-(id)initWithJSON:JSONString:(NSString*)JSONString
{
    self = [super init];
    if(self){
        //parse JSON
        _myValue = JSONString;
    }
    return self;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-07
    • 1970-01-01
    • 2017-10-30
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    相关资源
    最近更新 更多