Very new to Objective c. My interface and implementation looks like this:
// MyAuth.h
// #interface
+ (instancetype)sharedToken;
// MyAuth.m
//#implementation
+ (instancetype)sharedToken {
static MyAuth *_sharedToken = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedToken = [[NSUserDefaults standardUserDefaults] valueForKey:#"token"];
});
return _sharedToken;
}
Now I'm trying to get the length of the sharedToken but am stuck here. What I've tried
[MyAuth sharedToken].length // doesn't work
How can I get the length of `sharedToken
You want a string pulled from NSUserDefaults to be accessible everywhere in your app, via this method.
The return type of the method needs to be the type of the object you're actually returning:
+ (NSString *)sharedToken;
instancetype says that the method returns an instance of the class which runs the method.
The pointer you use for the string should also have the correct type:
static NSString *_sharedToken = nil;
Now the compiler will let you send length to the result of the method call.
Related
I created a MyService class, I made it a singleton like this:
header :
#interface MyService : NSObject
+(MyService *)sharedInstance;
#end
implementation:
#implementation MyService {
dispatch_queue_t queue;
}
+ (VADispatchQueue *)sharedInstance {
static MyService *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyService alloc] init];
queue = dispatch_queue_create("my.custom.queue", NULL);
});
return sharedInstance;
}
...
#end
As you see above, I defined a private variable dispatch_queue_t queue in MyService class.
In another class, I try to access this private variable by:
dispatch_queue_t queue = [[MyService sharedInstance] valueForKey:#"queue"];
But above code causes run-time error:
caught "NSUnknownKeyException", "[<MyService 0x7a068440> valueForUndefinedKey:]: this class is not key value coding-compliant for the key queue."
Why I get this error? (I have another place use the same way to access a BOOL private variable of another class and it works fine there)
As I explained you yesterday (today?) key-value coding forms accessor selectors from keys. You do not have accessor methods to be executed o the selector. (For the protocol: It can access ivars directly, see +accessInstanceVariablesDirectly, but you do not want to do that.)
Make it a property. This will automatically add accessors. Or implement accessors manually.
Problem is because it's ivar variable and KVC working with properties. So you need to create property instead ivar variable.
I have a very specific issue where, if I have a swift class which inherits from an objective-c class, and it has a dynamic property.
Now, on the +initialize, I am injecting getter and setters into the swift(:NSObject) class, and these work no problem, except for a slight issue when setting values from an init overload.
So, my swift class looks like this:
class TestClass: BaseClass {
dynamic var testStringProperty: String?
init(initialValue: String) {
super.init()
self.testStringProperty = initialValue;
// does not trigger the get/set methods
// a po self.testStringProperty will output 'nil'
let xyz = self.testStringProperty;
// xyz is actually set to the value of initialValue, but it does not trigger the getter.
}
}
And the objective-c class that bases the swift is as follows:
static id storedVar;
#implementation BaseClass
+ (void)initialize {
// we are going to exchange getter/setter methods for a property on a SwiftClass, crude but demonstrates the point
if(![[self description] isEqualToString:#"BaseClass"]) {
IMP reader = (IMP)getPropertyIMP;
IMP writer = (IMP)setPropertyIMP;
const char* type = "#";
NSString* propertyName = #"testStringProperty";
IMP oldMethod = class_replaceMethod([self class], NSSelectorFromString(propertyName), reader, [[NSString stringWithFormat:#"%s#:", type] UTF8String]);
NSString* setMethod = [NSString stringWithFormat:#"set%#%#:", [[propertyName substringToIndex:1] uppercaseString], [propertyName substringFromIndex:1]];
oldMethod = class_replaceMethod([self class], NSSelectorFromString(setMethod), writer, [[NSString stringWithFormat:#"v#:%s",type] UTF8String]);
}
}
static id getPropertyIMP(id self, SEL _cmd) {
return storedVar;
}
static void setPropertyIMP(id self, SEL _cmd, id aValue) {
storedVar = aValue;
}
#end
Long story short, whilst in the call to init(initialValue: String), the getters and setters are not triggered, but immediately after the call to init has completed they work.
This is despite the call to initialize completing successfully and the methods being replaced.
But outside of the init function, the get/set behave as expected.
Here is where it get's called.
let test = TestClass(initialValue: "hello");
test.testStringProperty = "hello"
A po test.testStringProperty after the creation of the object, will output nil. But the subsequent assignment, triggers all the correct methods.
It only fails when assigning within the init. Everywhere else it works like a charm.
I would like to get this to work within the initializer if possible, i'm not sure if there is another way to work around it.
Here is a link to the sample app that replicates the issue:
https://www.dropbox.com/s/5jymj581yps799d/swiftTest.zip?dl=0
I am trying to use a singleton for Core Data. Previously, I've been successfully able to do it by creating a class CoreDataStack.h/.m, calling the default stack method below, and its respective managed object context, in Objective-C, and works very well:
//RETURNS CoreDataStack
+ (instancetype)defaultStack {
static CoreDataStack *defaultStack;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defaultStack = [[self alloc]init];
});
return defaultStack;
}
However, I am using a Swift project, and I've been struggling to convert this into the latest Swift syntax. How would I go about creating this? This is my attempt so far:
class func defaultStack() -> Self {
var defaultStack: CoreDataStack
var onceToken: dispatch_once_t = 0
dispatch_once(&onceToken) {
defaultStack = self.init()
}
return defaultStack
}
and my Xcode generated error:
To create a singleton, use Krakendev's single-line singleton code:
class CoreDataStack {
// Here you declare all your properties
static let sharedInstance = User()
private init() {
// If you have something to do at the initialization stage
// you can add it here. It will only be called once. Guaranteed.
}
// Add the rest of your methods here
}
You will call your methods and properties as CoreDataStack.sharedInstance().property and CoreDataStack.sharedInstance().method(). I recommend using something shorter instead of sharedInstance, like service.
This solution applies in general, not only in your Core Data case.
I try to get a static variable from a class so I do this
in file Login.h
+ (instancetype)setToken:(NSString *)aToken;
In file Login.m I do this
static NSString* token;
.......
+(instancetype)setToken:(NSString *)aToken
{
token = [aToken copy];
return aToken;
}
so I can get value
[Login setToken:token]
But I don't know how to get this value in another class
You have to provide a class getter method as well:
+ (void)setToken:(NSString *)token;
+ (NSString *)token;
However using a singleton is the preferred way of doing this, allowing you to use a #property.
Create a getter method for that. This method will return that static variable value.
Add signature of that method to Login.h file.
+ (NSString *) getUniqueToken;
Relevant method in Login.m class.
+ (NSString *) getUniqueToken {
return token;
}
As it is a class method you can direclty access with out creating object of login class.
Call above method in other controller class, It will return token string.
[Login getToken];
I want to make myself things easier so I'm creating a dictionary that is used by other function (to reach key by object or object by key) but that dictionary is always static. Is this fine way to do it or I need property or something else?
+ (NSDictionary *)dictionaryWithCategoriesAndStrings
{
return #{
kNewsCategoryAll : #(NewsCategoryAll),
kNewsCategoryRadio : #(NewsCategoryRadio),
kNewsCategoryEconomics : #(NewsCategoryEconomics),
kNewsCategoryCulture : #(NewsCategoryCulture),
kNewsCategorySport : #(NewsCategorySport),
kNewsCategoryTravel : #(NewsCategoryTravel),
kNewsCategoryMusic : #(NewsCategoryMusic),
kNewsCategorySociety : #(NewsCategorySociety),
kNewsCategoryHealth : #(NewsCategoryHealth)
};
}
So now I always access this same dictionary through function [self dictionaryWithCategoriesAndString];
Note: Those are keys are static strings declared at top and objects are NSNumbers with integer.
Rather than exposing the static to the entire class, you could create it within the method, and initialise it only once with gcd:
This is thread safe.
+ (NSDictionary *)dictionaryWithCategoriesAndStrings {
static NSDictionary *dict;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dict = #{
kNewsCategoryAll : #(NewsCategoryAll),
kNewsCategoryRadio : #(NewsCategoryRadio),
kNewsCategoryEconomics : #(NewsCategoryEconomics),
kNewsCategoryCulture : #(NewsCategoryCulture),
kNewsCategorySport : #(NewsCategorySport),
kNewsCategoryTravel : #(NewsCategoryTravel),
kNewsCategoryMusic : #(NewsCategoryMusic),
kNewsCategorySociety : #(NewsCategorySociety),
kNewsCategoryHealth : #(NewsCategoryHealth)
};
});
return dict;
}
You will be creating a new NSDictionary every time you call this method, so you won't really be accessing the same dictionary as it will just be a new identical one each time. You won't be able to make a property either if you're using it statically. Maybe something a little more like this just so you are accessing the same dictionary each time.
To access this in an instance method, you could use [[self class] dictionaryWithCategoriesAndStrings].
static NSDictionary* dict;
+ (NSDictionary *)dictionaryWithCategoriesAndStrings
{
if(dict == nil)
{
dict = #{
kNewsCategoryAll : #(NewsCategoryAll),
kNewsCategoryRadio : #(NewsCategoryRadio),
kNewsCategoryEconomics : #(NewsCategoryEconomics),
kNewsCategoryCulture : #(NewsCategoryCulture),
kNewsCategorySport : #(NewsCategorySport),
kNewsCategoryTravel : #(NewsCategoryTravel),
kNewsCategoryMusic : #(NewsCategoryMusic),
kNewsCategorySociety : #(NewsCategorySociety),
kNewsCategoryHealth : #(NewsCategoryHealth)
};
}
return dict;
}
Almost right. Every time that selector is executed, a new NSDictionary is created. That is bad. It should only be created once, and it should only be created lazily.
#property (strong, nonatomic) NSDictionary *categoryDict;
- (NSDictionary *) categoryDict
{
if( !_categoryDict)
{
_categoryDict = #{ #"Key" :#"value" , ....};
}
return _categoryDict;
}
Now the dictionary is only created once. and you can get to the dictionary using dot notation.