7

KVC を使用して ivar にアクセスしようとした後、プライベートおよび保護された ivar に保護がないことに気付きました。ivar (プライベートまたは保護されたキーワード) の前に何を置いても問題ありません。KVC メソッド「setValue」を使用する場合、ivar は常にパブリック ivar です。これは私のコードで、7 つの ivar とプロパティのすべてがクラス インスタンスの外で変更可能です。

//************ interface file ***************//
@interface MyClass : NSObject {
@public    
  NSNumber *public_num;
@protected 
  NSNumber *protected_num;
@private 
  NSNumber *private_num;
  NSNumber *private_property;
}
@property (retain) NSNumber *public_property;
@property (retain) NSNumber *private_property;
@end

//********* implementation file *********//
@interface MyClass(){
@private
  NSNumber *very_private_num;
}
@property (retain) NSNumber *very_private_property;
@end

@implementation MyClass
@synthesize public_property, private_property, very_private_property;
@end

//****** main **********//
MyClass *myClass = [[MyClass alloc] init];

[myClass setValue:[NSNumber numberWithInt:1] forKey:@"public_num"];
[myClass setValue:[NSNumber numberWithInt:2] forKey:@"protected_num"];
[myClass setValue:[NSNumber numberWithInt:3] forKey:@"private_num"];
[myClass setValue:[NSNumber numberWithInt:4] forKey:@"public_property"];
[myClass setValue:[NSNumber numberWithInt:5] forKey:@"private_property"];
[myClass setValue:[NSNumber numberWithInt:6] forKey:@"very_private_num"];
[myClass setValue:[NSNumber numberWithInt:7] forKey:@"very_private_property"];

NSNumber *l_public_num = [myClass valueForKey:@"public_num"];
NSNumber *l_protected_num = [myClass valueForKey:@"protected_num"];
NSNumber *l_private_num = [myClass valueForKey:@"private_num"];
NSNumber *l_public_property = [myClass valueForKey:@"public_property"];
NSNumber *l_private_property = [myClass valueForKey:@"private_property"];
NSNumber *l_very_private_num = [myClass valueForKey:@"very_private_num"];
NSNumber *l_very_private_property = [myClass valueForKey:@"very_private_property"];

NSLog(@"public_num = %@, protected_num = %@, private_num = %@, public_property = %@, private_property = %@, very_private_num = %@, very_private_property = %@", l_public_num, l_protected_num, l_private_num, l_public_property, l_private_property, l_very_private_num, l_very_private_property);

出力の結果 > public_num = 1、protected_num = 2、private_num = 3、public_property = 4、private_property = 5、very_private_num = 6、very_private_property = 7。

private インターフェイスで宣言された ivar であっても、クラス外では変更可能です。では、カプセル化を強制し、「ivar を悪意のある他のプログラマーから保護する」にはどうすればよいでしょうか :)

4

5 に答える 5

10

NSObject はNSKeyValueCoding非公式プロトコルに準拠しています。これは と を定義setValue:forKey:valueForKey:ます。インスタンス変数への直接アクセスを含む特定の検索ルールに従って、キーの値にアクセスする方法を検索しsetValue:forKey:ます。この直接アクセスは、NSKeyValueCoding 非公式プロトコルの一部であるメソッドによって制御されます。このメソッドは、デフォルトで を返します。これにより、これらのメソッドはインスタンス変数に直接アクセスできるようになり、その結果、インスタンス変数自体は実際には非公開になりません。それらは直接アクセスからまだプライベートです。valueForKey:accessInstanceVariablesDirectlyYES

これを解決するには、上記のメソッドとNSKeyValueCoding非公式プロトコルで定義されたメソッドをオーバーライドして、アクセスを防止する必要があります。

Abizern が述べたように、Objective-C にはプライベート メソッドの概念がないため、プライベート変数のプロパティには引き続きアクセスできます。

于 2011-05-25T10:57:18.110 に答える
4

@property本当にプライベートのままにしておきたい場合は、iVarのを宣言しないでください。

プライベートではなくなったのはiVarではありません。Objective-Cランタイムには、プライベートメソッドの概念がありません。@property@を使用するとsynthesizeKVC準拠のアクセサメソッドが生成されるため、バッキングiVarがプライベートであるかどうかに関係なく、いつでもメソッドを呼び出すことができます。

しかし、それはあなたが思うほど悪くはありません。使用しているメソッドを使用しても、iVarは直接変更されません。セッターを通過します。追加の保護が必要な場合は、必要な保護を実装する独自のセッターを作成できます。

iVarをとして宣言し、@privateKVCに準拠させない場合、プライベートのままになります。もちろん; その場合、そのiVarでKVCまたはKVOを使用することはできませんが、それらを使用できるようにしたい場合は、プライベートiVarとして宣言しないでください。

于 2011-05-25T10:10:59.437 に答える
1

この古い質問に 2 セント追加します。

「->」演算子を使用した変数へのアクセスを防ぐためにもある@privateと思います。@protected

myPrivateVar以下のように宣言された iVar があるとします。

@interface MyClass:NSObject{
  @public
    NSArray *myPrivateVar;
}

したがって、以下のクラスメソッドを実装して戻りNO、iVar に対して宣言されたアクセサーがない場合でも:

+accessInstanceVariablesDirectly{
    return NO;
}

を使用すると、変数に引き続きアクセスできますmyClassObj->myPrivateVar

一方、 to を作成して@public@private実装しないaccessInstanceVariableDirectly場合でも、KVC を使用して変数にアクセスできます。

[myClassObj valueForKey:@"myPrivateVar"];

(および 経由ではアクセスできませんmyClassObj->myPrivateVar)

したがって、iVar を完全に非公開にするには、 として宣言し@privateaccessInstanceVariablesDirectlyreturn を実装する必要がありますNO

于 2013-06-18T14:51:38.773 に答える
0

kvc エントリをオーバーライドして禁止します。

@implementation MONObject

- (id)valueForKey:(NSString *)key
{
/* enforce it */
    return nil;
}

- (void)setValue:(id)value forKey:(NSString *)key
{
/* enforce it */
}

/* and so on */

@end
于 2011-05-25T10:44:40.923 に答える