Access int from Another Objective-C Class - ios

I've trying to get an int from another class and it just says that the number is 0 (but it's not).
This is in Class2.h:
#interface Class2 : SKScene <SKPhysicsContactDelegate>{
Class1 * class;
}
This is in Class2.m:
NSLog(#"%i", class.thisint);
This is in Class1.h:
#property (assign, nonatomic) int thisint;
This is in Class1.m (in viewDidLoad):
thisint = 5;
The NSLog is being called well after the viewDidLoad method but it just keeps saying 0. How do I get this int from Class1? I don't know if the fact that Class2 is an SKScene affects this...

class is an existing method on NSObject and I would hope that you've just used that name for the purposes of this question - if not, please change the name of the variable, it will only lead to confusion.
What do you see if you log class:
NSLog(#"%#",class);
(Put that next to where your existing log is)
How and where are you assigning to the class variable?
A value of 0 probably means one of two things:
class is nil. This means you haven't assigned it anywhere. You don't magically get a value in a property just because you've declared one
class is a different instance to the one you think it is. This is a common beginner mistake, where you've done something like
class = [[Class2 alloc] init];
Which creates a new instance. You need to get a reference to the existing instance, which I can't tell you how to do without seeing more code.

Related

Why is instancetype used?

Can someone please explain to me (in simple terms) why an instancetype is used in Objective-C?
- (instancetype) init {
self = [super init];
if (self) {
// Custom initialization
}
return self;
}
It's to increase type safety.
Back in the old days, initialisers just returned an object of type id (any object).
With normal initialisers (those that begin with "init", "alloc" or "new"), this wasn't usually a problem. The compiler would automatically infer the type that it returned and therefore restrict any method calls on the object to the instance methods of that class.
However, this was a problem with static convenience initialisers or "factory methods" that didn't necessarily follow the same naming convention - therefore it was unable to apply the same type safety.
This means that with a class like this:
#interface Foo : NSObject
+(id) aConvenienceInit;
#end
The compiler would accept code like this:
NSArray* subviews = [Foo aConvenienceInit].subviews;
Why? Because the returned object could be any object, so if you try and access a UIView property - there's no type safety to stop you.
However, now with instancetype, the result you get back is of type of your given instance. Now with this code:
#interface Foo : NSObject
+(instancetype) aConvenienceInit;
#end
...
NSArray* subviews = [Foo aConvenienceInit].subviews;
You'll get a compiler warning saying that the property subviews is not a member of Foo*:
Although it's worth noting that the compiler will automatically convert the return type from id to instancetype if your method begins with "alloc", "init" or "new" - but nonetheless using instancetype wherever you can is a good habit to get into.
See the Apple docs on instancetype for more info.
Imagine two classes:
#interface A : NSObject
- (instancetype)init;
#end
#interface B : A
#end
The init method from A is inherited to B. However, in both classes the method has a different return type. In A the return type is A and in B the return type is B.
There is no other way to declare the return type for initializers correctly. Note that most programming languages with classes don't even have return types for constructors, therefore they completely avoid the issue.
This is the reason why Obj-C needs instancetype but of course it can be used outside initializers, too.
It is important to use instancetype instead of id in Objective-C if you are also using this code in Swift. Consider the following class declaration:
#interface MyObject : NSObject
+ (id)createMyObject;
- (void)f;
#end
If you want to create a MyObject instance in Swift 5.3 with createMyObject and then call f for this object, you will have to do the following:
let a = MyObject.createMyObject()
(a as? MyObject)?.f()
Now replace id with instancetype in MyObject to have the following Swift code:
let a = MyObject.create()
a?.f()
As you can see now, you can use MyObject.create() instead of MyObject.createMyObject(). And you don't need to use (a as? MyObject) since a is defined as MyObject? and not as Any.

how to set labels from another class

I have problem with set text on labels. Labels are declarated in class1 but I want to use it and set it in class2 where I want to set data dependent on the selected row in tableView (is implemented in class2)
my declatation in class1:
#property (weak, nonatomic) IBOutlet UILabel *trackNameDetailsLabel;
my method in class2 (I try this but does not work):
-(void)setLabels {
self.trackNameDetails = self.result.trackName;
}
result.trackName is recall to data which are stored in url file
Thanks in advance.
You can give class 2 a reference of class 1 from itself by making a variable like Class1 *referenceOf1 = self and adding #class Class1; to the top of Class 2. Then, in class 2, you can make an instance of class 1 and calling that reference.
Alternatively, you can pass data through a singleton, which in my opinion is nicer and avoids memory leaks. Here's a link to learn more about singletons.
http://www.galloway.me.uk/tutorials/singleton-classes/
Looks like you have trackNameDetails for class 2, but you want to set value to trackNameDetailsLabel in class 1
So the code
-(void)setLabels {
self.trackNameDetails = self.result.trackName;
}
will only set the property trackNameDetails in class 2.
You need give a reference, which can be instance of class 1 to class 2 like Cole said.
In class 2,
#property(strong, nonatomic) Class1 * class1;
-(void)setLabels {
class1.trackNameDetails = self.result.trackName;
}
Remember to set class1 to a instance of Class1 before using this method

Logic/iOS - Override certain values depending on if user entered or not

I am looking for a way to properly perform the following.
I have multiple values in an object that are given default values (some a physical number, other calculated). The user selects a few parameters and the rest are populated for them.
After the values are populated the user can then overwrite any value of their choosing which then may cause values to be re-calculated. If the value is a calculated value that the user has entered I don't want it to change.
Take for example the following:
Class values {
NSString *userSelected:
double value1;
double value2;
double value3;
double calc1;
double calc2;
double calc3;
}
The user then selects (From a picker) values.userSelected. Upon selection, values 1 - 3 and calc 1 - 3 are assigned/calculated to their "default values".
The user can then go in and edit say value1. Once changed calc1-3 will re-calculate if they use value1. Now the user can also overwrite the calc values. So if the user overrides calc1 and then changes value1 I DO NOT want calc1 to change again since it was changed by the user.
One way I thought to do this was duplicate each value with a default and if the non-default is set return that instead:
ie
Class values {
double value1;
double defaultValue1; ... etc.
}
Hence if the non-default value is set then use that, else use the default value. This just seems like an inefficient way of doing it. Does anyone have a better thought process on how to do this. My class is around 20 properties so I'd rather not require 2 properties per variable. I am programming in iOS but this is more a methodology question vs a specific piece of code. If anything is unclear please feel free to ask.
Thanks,
DMan
One thing that could do what you're looking for: accessor overrides. Basically, you declare in your class a bunch of values using #property syntax, then do some stuff under the hood in the implementation, including overriding the getter/setters. For example:
//in MyClass.h
#interface MyClass : NSObject
#property (nonatomic, assign) double value1;
#property (nonatomic, assign) double calc1;
#end
//in MyClass.m
#implementation MyClass {
BOOL _calc1Changed;
}
//you should default that flag to NO, so...
- (id)init {
_calc1Changed = NO;
}
- (void)setValue1:(double)newValue1 {
if (!_calc1Changed) [self calculateCalc1]; //define this calculation also in this file
value1 = newValue1; //value1 is the synthesized ivar for the property you declared
}
And of course, somewhere you'll need to call _calc1Changed = YES; whenever the user sets calc1 manually, possibly in a similarly constructed override. Basically, the result is that every time you call myClassInstance.value1 = something or [myClassInstance setValue1:something] these checks will be performed and extra functionality can be performed to validate/respond to inputs.

Using a static variable to reference instances of a class in Objective C?

I'm brand new to Objective C, and this may be somewhat of a lame question but:
I'm trying to make an iOS game, in which there is a class 'Monster' which generates a new instance of Monster every second or so, I want to be able to keep track of each Monster in order to use/manipulate it somehow.
Currently I'm trying to issue each Monster an unique ID,
e.g something like this:
//Incorrect Syntax ...
Class Monster extends CCSprite
public static global_id = 0;
public instance_id;
init() {
instance_id = global_id;
global_id ++;
}
How would I manage this in the header/implementation file for class Monster?
It seems like "static" 'doesn't exist' in Objective-C.
You'd normally work around the problem by:
sticking to the one-class-per-source-file rule;
putting a suitable global variable within that file;
marking the global variable as static, which in C terms means "not accessible from outside of this compilation unit" (and one source file is one compilation unit if you don't go out of your way with the preprocessor).
So, interface:
#interface AEMonster: CCSprite
#property (nonatomic, readonly) int instanceID;
#end
Implementation:
static int globalID = 0;
#implementation AEMonster
- (instancetype)init
{
self = [super init];
if(self)
{
_instanceID = globalID;
globalID ++;
}
return self;
}
#end
Your example didn't look like pure Objective-C. Objective-C does support static definitions. What you're describing is a classic Factory/Singleton pattern, and it would look like this:
MyClass.h:
#interface MyClass : NSObject
+ (id)getInstance;
#end
MyClass.m:
#import "MyClass.h"
+ (id) getInstance
{
static MyClass *myClass = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
myClass = [[self alloc] init];
});
return myClass;
}
This is the singleton part of the pattern, where you call MyClass *c = [MyClass getInstance]; to get a reference to the instance. Only one instance will ever exist, and this is great for things where you want something semi-global but with a better pattern (things like network services are great examples).
A Factory pattern is just a step beyond this. You build MyClass exactly the same way, but instead of a getInstance() method you would have a createMonster() method. That would take any parameters required to create the type of Monster you wanted (this pattern is especially useful when you're going to have a Monster base class and then sub-classes of specific Monster types).
That's where you would generate your unique ID. Just add another static member variable inside the factory function and you can increment it each time it's called. That's a really naive unique ID generator, though - you probably want to make sure what you do is thread-safe, too. (That's another story.)

property not found on object Type (custom) xcode

the strangest thing happened. Although I don't think I touched anything in that class, suddenly it started telling me it couldn't find an array in a class...
Here are the errors:
basically it cannot access the mutable array in baseobject (custom Car.h type)
(semantic issue: property objectReadyForCoreDatabase not found in object of type CarPacket (false, because it is declared))
if([baseObject.objectsReadyForCoreDataBaseInput count]<kLenght )
{
}
car packet .h
#import <Foundation/Foundation.h>
#import "ResponsePacket.h"
#interface CarPacket : ResponsePacket
#property (nonatomic, copy) NSString *objectID;
#property (nonatomic, retain) NSMutableArray *objectsReadyForCoreDataBaseInput;
#property (nonatomic, assign) NSInteger timeStamp;
#end
It is weird because on the same page where I get the error if I type object.objectID it recognizes that but not object.objectReadyForCoreDataBaseInput (also it just suddenly stopped working)
Please let me know if you have any ideas... Thank you
I tried restoring to previous snapshots and it had no effect... it still showed the error (even though I know on that date it didn't)
You haven't shared much about the context of where you're making the call (and seeing the error). That said, my guess would be one of two things: The calling class isn't familiar with the receiving class (CarPacket), or, the calling class doesn't know that baseObject is a CarPacket.
Where are you calling from? Make sure the calling class imports the headers. Since I don't know where you're calling from, let's say it's from within UnknownClass:
UnknownClass.m
#import UnknownClass.h
#import CarPacket.h // This should make your class familiar
#implementation UnknownClass
The other thing is that you need to make sure that at the time you're touching the baseObject, your UnknownClass instance knows that it is dealing with a CarPacket instance, e.g.:
- (void)someMethodOfUnknownClass
{
CarPacket *baseObject = (CarPacket *)baseObject; // Cast baseObject if it hasn't been declared as a CarPack in scope...
if([baseObject.objectsReadyForCoreDataBaseInput count]<kLenght )
{
}
}

Resources