Objective-C Writing Common Retrieval and Installation Methods

In my project, I have a settings class with properties with customizable adjusters who access NSUserDefaultsto make things easier. The idea is that the class Settingshas

@property NSString *name

which has a custom getter that gets the name value from NSUserDefaultsand a setter that stores the new value there. Thus, in the whole project, I interact with the Settings class only to manage user settings. The fact is that it seems too repetitive to write all getters and setters (I have about 50 properties), and I would like to create one setter and one getter that will work for all variables. My only problem is how to get the variable name in the customizer.

Finally, the question arises: is it possible to find out inside the receiver or setter for which the property is the called function?

If you have a different approach, I would also appreciate it, but given that I would like to keep all the materials NSUserDefaultsin one class, I can’t come up with an alternative that does not include recording 50 getters and setters.

Thank!

+4
source share
6 answers

I found your question very interesting, and I said to myself: "The decision is made!".

I created this project on Github.

Basically, all you have to do is subclass the VBSettings class and then declare the properties, for example:

@interface MySettings : VBSettings

@property (strong, nonatomic) NSString *hello;

@end

The value "hello" will be stored in NSUserDefaults using the "hello" key. Usage example:

MySettings settings = [[MySettings alloc] init];
settings.hello = "World!"; //The value is saved in NSUserDefaults
NSLog(@"%@", settings.hello); //The value is restored from NSUserDefaults.
+2
source

, :

- (void)setName:(NSString *)name {
   [[NSUserDefaults standardUserDefaults] setObject:name forKey:@"name"];
   [[NSUserDefaults standardUserDefaults] synchronize];
}

- (NSString *)name {
   return [[NSUserDefaults standardUserDefaults] objectForKey:@"name"];
}

:

- (id)objectForKey:(NSString *)key {
   return [[NSUserDefaults standardUserDefaults] objectForKey:key];
}
- (void)setObject:(id)object forKey:(NSString *)key {
   [[NSUserDefaults standardUserDefaults] setObject:object forKey:key];
   [[NSUserDefaults standardUserDefaults] synchronize];
}

, - , . :

static NSString *const kName = @"name";
static NSString *const kLastName = @"lastName";
+3

. , .

@interface DBObject : NSObject<NSCoding>
+ (instancetype)sharedObject;
@end

@interface NSObject(SubScription) 
- (id)objectForKeyedSubscript:(id)key;
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
@end

:

+ (instancetype)sharedObject {
   static DBObject *sharedObject = nil;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
     sharedObject = [[DBObject alloc] init];
   });
   return sharedObject;
}

- (id)objectForKeyedSubscript:(id)key {
   return [[NSUserDefaults standardUserDefaults] objectForKey:key];
 }

- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key {
   [[NSUserDefaults standardUserDefaults] setObject:obj forKeyedSubscript:key];
   [[NSUserDefaults standardUserDefaults] synchronize];
 }

:

 // You saved it in NSUserDefaults
[DBObject sharedObject][@"name"] = @"John"; 

// You retrieve it from NSUserDefaults
NSLog(@"Name is: %@", [DBObject sharedObject][@"name"]); 

, .

+2

KVO .

:.

@interface Settings : NSObject

@property NSString *one;
@property NSString *two;

@end

@implementation Settings

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self addObserver:self forKeyPath:@"one" options:NSKeyValueObservingOptionNew context:NULL];
        [self addObserver:self forKeyPath:@"two" options:NSKeyValueObservingOptionNew context:NULL];
    }
    return self;
}

- (void)dealloc
{
    [self removeObserver:self forKeyPath:@"one"];
    [self removeObserver:self forKeyPath:@"two"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    NSLog(@"Key: %@, Change: %@", keyPath, change);
}

@end

:

Settings *settings = [[Settings alloc] init];
settings.one = @"something for one";

:

: , : {     kind = 1;     new = "- "; }

0

Getter Setter .

, :

- (id)_getter_
{
    return [[NSUserDefaults standardUserDefaults] objectForKey:NSStringFromSelector(_cmd)];
}

- (void)_setter_:(id)value 
{
    //This one _cmd name has "set" in it and an upper case first character
    //This could take a little work to parse out the parameter name
    [[NSUserDefaults standardUserDefaults] setObject:object forKey:YourParsedOutKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

:

+(void)synthesizeForwarder:(NSString*)getterName
{
    NSString*setterName=[NSString stringWithFormat:@"set%@%@:",
          [[getterName substringToIndex:1] uppercaseString],[getterName substringFromIndex:1]];
    Method getter=class_getInstanceMethod(self, @selector(_getter_));
    class_addMethod(self, NSSelectorFromString(getterName), 
                    method_getImplementation(getter), method_getTypeEncoding(getter));
    Method setter=class_getInstanceMethod(self, @selector(_setter_:));
    class_addMethod(self, NSSelectorFromString(setterName), 
                    method_getImplementation(setter), method_getTypeEncoding(setter));
}

, :

+(void)load  
{
    for(NSString*selectorName in [NSArray arrayWithObjects:@"name", @"anything", @"else", @"you", @"want",nil]){
       [self synthesizeForwarder:selectorName];
    }
}

, . , , , , . 2 StackOverflow .

Getters Setters.

.

0

, , setObject:forKey: objectForKey:.

. , .

  • , :

    @property NSString *something;
    @property NSString *somethingElse;
    
  • , , :

    @dynamic something,somethingElse;
    
  • methodSignatureForSelector, :

    -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {if (SelectorIsGetter(aSelector))
       return [NSMethodSignature signatureWithObjCTypes:"@@:"];
     if (SelectorIsSetter(aSelector))
       return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
     return nil;
     }
    

, forwardInvocation: , .

SelectorIsGetter SelectorIsSetter . , , NSStringFromSelector(aSelector), , , , : something somethingElse setSomething: setSomethingElse: .

  1. forwardInvocation:, :

    -(void)forwardInvocation:(NSInvocation *)anInvocation
    {if (SelectorIsGetter(anInvocation.selector))
       {NSString *s=[self objectForKey:NSStringFromSelector(anInvocation.selector)];
        [anInvocation setReturnValue:&s];
        return;
        };
     if (SelectorIsSetter(anInvocation.selector))
        {NSString *s;
         [anInvocation getArgument:&s atIndex:2];
         [self setObjectForKey:UnmangleName(NSStringFromSelector(anInvocation.selector))];
         return;
         };
     [super forwardInvocation:anInvocation];
     }
    

... UnmangleName - , "setSomething:" "-".

, NSStrings, .

0

Source: https://habr.com/ru/post/1649179/


All Articles