Objective-C Class extensions - ios

I've started learning obj-C just recently so sorry if I'm missing something obvious.
I want to access "passCode" (extension) with clpPlayerStats object, but it's impossible to do ("Property not found on object..."). Is there any simple way to fix this?
clpPlayerStats.h
#import <Foundation/Foundation.h>
#interface clpPlayerStats : NSObject
#property(nonatomic, copy) NSString* name;
#end
clpPlayerStats.m
#import "clpPlayerStats.h"
#interface clpPlayerStats()
#property (nonatomic) unsigned int passCode;
#end
#implementation clpPlayerStats
#end
main.m
#import <Foundation/Foundation.h>
#import "clpPlayerStats.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
clpPlayerStats *clapslock = [[clpPlayerStats alloc] init];
NSString *username = [NSString stringWithFormat:#"xxxPussySlayerxxx"];
clapslock.name = username;
clapslock.passCode = 12; // <------ "Property not found on object..."
}
return 0;
}

First, class names should always start with second letters.
Secondly, Class Extensions extend the #interface of the class. And, with all things C, whether or not a declaration of anything can be seen is entirely dependent on whether the compiler can see the declaration at the time of use.
So, if you want to declare something that is semi-private, then you would typically move your #interface ClpPlayerStats() extension to a Private header file; ClpPlayerStats_Private.h. Then, if you want to access the "private" API, you #import ClpPlayerStats_Private.h.
There really isn't a formal notion of privacy in Objective-C. Just visibility to the compiler.

With this code:
#interface clpPlayerStats()
#property (nonatomic) unsigned int passCode;
#end
you are declaring a private property. If you want to use passCode outside the scope of your class you have to add in the public interface:
#import <Foundation/Foundation.h>
#interface clpPlayerStats : NSObject
#property(nonatomic, copy) NSString* name;
#property (nonatomic) unsigned int passCode;
#end
and remove the interface in the .m

Related

Accessing an externed variable from objective-c in swift

I have an iOS project that uses both Obj-C and Swift.
In main.m, I want to instantiate a variable to be accessed by Swift. The specific use case is to store the absolute time at main, and then measure time elapsed since main elsewhere.
Here's what my relevant files look like:
main.m
#import <UIKit/UIKit.h>
CFAbsoluteTime StartTime;
int main(int argc, char* argv[])
{
StartTime = CFAbsoluteTimeGetCurrent(); // This is what I want to access elsewhere.
#autoreleasepool {
...
}
}
myapp-Bridging-Header.h
#import "AppDelegate.h"
extern CFAbsoluteTime StartTime;
AppDelegate.h
#import <UIKit/UIKit.h>
extern CFAbsoluteTime StartTime;
#interface AppDelegate : NSObject <UIApplicationDelegate>{}
#property (nonatomic, strong) IBOutlet UIWindow* window;
// ... other irrelevant #property
#end
And then in the actual .swift file, I'm just trying to access StartTime without declaring anything (as I thought it worked since it's being externed), but I'm getting an unresolved identifier error.

Property Inheritance in Objective C

I want to inherit my base class properties and methods which will be used by my several derived classes. I want these properties and methods to be exactly protected so that they will only be visible in derived class and not to any external class. But it always gives me some errors.
#interface BasePerson : NSObject
#end
#interface BasePerson ()
#property (nonatomic, strong) NSMutableArray<Person*>* savedPersons;
#property (nonatomic) BOOL shouldSavePerson;
#end
#interface DerivedPerson1 : BasePerson
#end
#implementation DerivedPerson1
- (instancetype)init
{
if (self = [super init]) {
self.savedPersons = [NSMutableArray array];
self.shouldSavePerson = NO;
}
return self;
}
It always gives me an error that
Property 'savedPersons' not found on object of type 'DerivedPerson1 *'
Property 'shouldSavePerson' not found on object of type 'DerivedPerson1 *'
How i can make use of inheritance in Objective C, I don't want savedPersons and shouldSavePerson properties to be visible to external classes. I only want them to visible in my base class and all the derived classes.
Any help will be great. Thanks
This is not something that the objectiveC really support. There are some ways though. So lets see.
If you put a property in the source file class extension then it is not exposed and you can not access it in the subclass either.
One way is to put all of the subclasses into the same source file as the base class. This is not a good solution at all as you do want to have separate files for separate classes.
It seems logical to import the BaseClass.m in the SubClass source file but that will produce a linker error saying that you have duplicate symbols.
And the solution:
Separate the extension into a separate header. So you have a MyClass
Header:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#end
Source:
#import "MyClass.h"
#import "MyClassProtected.h"
#implementation MyClass
- (void)foo {
self.someProperty = #"Some text from base class";
}
#end
Then you create another header file (only the header) MyClassProtected.h which has the following:
#import "MyClass.h"
#interface MyClass ()
#property (nonatomic, strong) NSString *someProperty;
#end
And the subclass MyClassSubclass
Header:
#import "MyClass.h"
#interface MyClassSubclass : MyClass
#end
And the source:
#import "MyClassSubclass.h"
#import "MyClassProtected.h"
#implementation MyClassSubclass
- (void)foo {
self.someProperty = #"We can set it here as well";
}
#end
So now if the user MyClassSubclass he will not have the access to the protected property which is essentially what you want. But the downside is the user may still import MyClassProtected.h after which he will have the access to the property.
Objective-C doesn't have member access control for methods, but you can emulate it using header files.
BasePerson.h
#interface BasePerson : NSObject
#property (strong,nonatomic) SomeClass *somePublicProperty;
-(void) somePublicMethod;
#end
BasePerson-Private.h
#import "BasePerson.h"
#interface BasePerson ()
#property (nonatomic, strong) NSMutableArray<Person*>* savedPersons;
#property (nonatomic) BOOL shouldSavePerson;
#end
BasePerson.m
#import "BasePerson-Private.h"
...
DerivedPerson1.h
#import "BasePerson-Private.h"
#inteface DerivedPerson1 : BasePerson
...
#end
Now any class that #imports BasePerson.h will only see the public methods. As I said though, this is only emulating access control since if a class #imports *BasePerson-Private.h" they will see the private members; this is just how C/Objective-C is.
We can achieve using #protected access specifier
#interface BasePerson : NSObject {
#protected NSMutableArray *savedPersons;
#protected BOOL shouldSavePerson;
}
DerivedPerson1.m
#implementation DerivedPerson1
- (instancetype)init
{
if (self = [super init]) {
self->savedPersons = [NSMutableArray array];
self->shouldSavePerson = NO;
}
return self;
}
#end
OtherClass.m
#import "OtherClass.h"
#import "BasePerson.h"
#implementation OtherClass
- (void)awakeFromNib {
BasePerson *base = [[BasePerson alloc]init];
base->savedPersons = #[];//Getting Error. Because it is not a subclass.
}
#end

Objective C - Avoid Import Loop

I want to connect two classes of mine and link each other with a property of each class. I broke down the main aspects to this example:
Ocean.h file:
#import <Foundation/Foundation.h>
#import "Fish.h"
#interface Ocean : NSObject
#property (nonatomic) NSArray *listOfFishesInOcean;
#end
Fish.h file:
#import <Foundation/Foundation.h>
#import "Ocean.h"
#interface Fish : NSObject
#property (nonatomic) Ocean *homeOcean; // Compiler: "Unknown type name Ocean"
#property (nonatomic) int age;
#end
What I wanna do in the end, is to manipulate the age property of an Fish object and be able to save it (listOfFishesInOcean, NSUserDefaults), as well as call a function in the Ocean object, when saving is completed. This way I'd always have the latest list of Fish-objects in my list of the Ocean-object.
My two problems here are:
How to avoid the import-loop, which causes the complier error, I think?
How should I implement the save & action workflow in the end?
I thought about solving this issue with notifications and observer but this way I'd still need to filter the notifications in any way, due to the fact that I've multiple Oceans with more Fishes.
Another idea to solve it, would be to give each Ocean object and Fish object an ID, which I would use as a key in NSUserDefaults again.
If anyone has some thoughts about it or other ideas, you are very welcome!
Import ".h" files only in ".m" file, like:
Ocean.h file:
#import <Foundation/Foundation.h>
#class Fish;
#interface Ocean : NSObject
#property (nonatomic) NSArray *listOfFishesInOcean;
#end
Ocean.m file:
#import "Ocean.h"
#import "Fish.h"
#implementation Ocean
#end
Fish.h file:
#import <Foundation/Foundation.h>
#class Ocean;
#interface Fish : NSObject
#property (nonatomic) Ocean *homeOcean;
#property (nonatomic) int age;
#end
Fish.m file:
#import "Fish.h"
#import "Ocean.h"
#implementation Fish
#end
I think one of the best approaches could be using the identifiers so you improve the performance.
#interface Ocean : NSObject
#property (nonatomic) int identifier;
#property (nonatomic) NSArray *listOfFishesInOcean;
#end
#interface Fish : NSObject
#property (nonatomic) int age;
#property (nonatomic) int parent_identifier;
#end
if you want to keep your approach:
#import <Foundation/Foundation.h>
#class Ocean;
#interface Fish : NSObject
#property (nonatomic) Ocean *homeOcean; // Compiler: "Unknown type name Ocean"
#property (nonatomic) int age;
#end
Fish.m
#import "Ocean.h"

objective c circular reference [duplicate]

This question already has answers here:
Errors when making circular reference imports
(2 answers)
Closed 8 years ago.
I have two custom NSObjects which reference each other, as below:
.h file class 1
#import <Foundation/Foundation.h>
#import "MyChildClass.h"
#interface MyParentClass : NSObject
#property (nonatomic, strong) NSString *Name;
#property (nonatomic) MyChildClass *myChild;
#end
.m file class 1:
#import "MyParentClass.h"
#implementation MyParentClass
#end
and...
.h file class 2:
#import <Foundation/Foundation.h>
#import "MyParentClass.h"
#interface MyChildClass : NSObject
#property (nonatomic) MyParentClass *myParent;
#end
.m file class 2:
#import "MyChildClass.h"
#implementation MyChildClass
#end
When I try and implement those as below, the project will not build, with the error "Arc Restrictions: Implicit conversion of an Objective-C pointer to 'int *' is disallowed with ARC"
View Controller implementation code:
MyParentClass *newParent = [[MyParentClass alloc] init];
MyChildClass *newChild = [[MyChildClass alloc] init];
newParent.Name = #"Johnny";
newParent.myChild = newChild;
newChild.myParent = newParent;
However, when I nest a second example into single .h/.m files, the project will build:
Nested .h file:
#import <Foundation/Foundation.h>
#class MyNestedClass;
#interface MyChildNestedClass : NSObject
#property (nonatomic, strong) MyNestedClass *myNested;
#property (nonatomic, strong) NSString *ChildName;
#end
#interface MyNestedClass : NSObject
#property (nonatomic, strong) MyChildNestedClass *myChild;
#property (nonatomic, strong) NSString *ParentName;
#end
Nested .m file:
#import "MyNestedClass.h"
#implementation MyChildNestedClass
#end
#implementation MyNestedClass
#end
I guess that by nesting the objects into a single file, I am somehow tricking ARC and that really I shouldn't be creating these circular references.
Could anyone suggest the correct way of nesting types like this?
What I am trying to achieve, is the following pseudo-scenario: Parent has a property of Child. Child has a property of the parent it is the child of.
Am I finding this difficult because I'm not supposed to do it (circular referencing), or am I missing something glaringly obvious?
Many thanks!
Do not #import "MyChildClass.h" in the parent class' header file, change it to
#class MyChildClass
and add the #import in the source file (.m)

Compiler error - iOS "expected ")" before "Question

What's wrong with the following code? Xcode 4 is saying that the two method declarations with "Question" don't compile due to an '"expected ")" before "Question"; message, as indicated in the comments in the code below. The Question class compiles and this code has been working previously. I made some changes to Questions, but backed them out to try to figure out this compile time error.
#import <Foundation/Foundation.h>
#import "Question.h"
#interface AppState : NSObject {
int chosenAnswer;
int correctAnswers;
int currentQuestionNumber;
// this will contain the hash table of question objects
NSMutableDictionary *questionHash;
}
#property (nonatomic) int chosenAnswer;
#property (nonatomic) int correctAnswers;
#property (nonatomic) int currentQuestionNumber;
#property (nonatomic, retain) NSDictionary *questionHash;
- (void) printQuestions;
- (void) printDescription;
- (void) addQuestion: (Question *) question; // <==== error
- (int) numberOfQuestions;
- (void) saveState;
- (void) resetState;
- (Question *) currentQuestion; // <===== error
#end
Here's Question.h:
#import <Foundation/Foundation.h>
#import "AppState.h"
#interface Question : NSObject {
NSString *questionTxt;
int correctAnswer;
int number;
// this will contain the hash table of questions_answer objects
NSMutableDictionary *answerHash;
}
#property (nonatomic, retain) NSString * questionTxt;
#property (nonatomic) int correctAnswer;
#property (nonatomic) int number;
#property (nonatomic, retain) NSMutableDictionary *answerHash;
-(void) addAnswer: (NSString *) answer;
- (NSMutableArray *) answerArray;
- (void) printDescription;
- (void) printAnswers;
- (NSString *) correctAnswerText;
- (Question *) currentQuestion;
#end
Circular dependency? AppState is importing Question and Question is importing AppState.
Forward-declare one of them to break the cycle, e.g. use #class Question before your AppState #interface statement, like this
#class Question;
#interface AppState : NSObject {
int chosenAnswer;
int correctAnswers;
int currentQuestionNumber;
// this will contain the hash table of question objects
NSMutableDictionary *questionHash;
}
...
Related question: #class vs. #import
When you #import "AppState.h" in Question you make a cyclic dependency.
It would be best to move #import "AppState.h" and #import "Question.h" to implementation part. In the header just leave
#class Question;
and
#class AppState;
before interface declaration.

Resources