Really new with objective c (building iphone app) and I'm trying to figure out how to properly understand how calling methods work (compared to c#, the most recent language I've been working with)
I have this implementation
#interface User : NSObject{
}
#property NSInteger Id;
#property NSString *email, *password;
-(BOOL)isValid;
#end
#implementation User
-(BOOL)isValid{
NSString *password = self.validateString:self.password;
NSString *email = self.email;
if(validUser){
return YES;
}else{
return NO;
}
}
EDIT: SOrry if it wasn't clear but this is the method I'm trying to call.
-(NSString *)validateString:(NSString *)string{
// process the string
return #"";
}
Basically I'm trying to create an instance in my view onclick of a button like so:
- (IBAction)btnSubmit:(id)sender {
// get values of email and password
// do an isvalid to check with web service.
User *user = [[User alloc] init];
user.email = #"email#email.com";
user.rawPassword = #"pass";
if(user.isValid){
// go to next page
}
else{
// else refresh current page
}
}
Is creating the instance on click and then passwing the values to process inside the instance a good practice?
Thanks!
No need of creating it's own object there. You can use the current object for doing this:
- (IBAction)btnSubmit:(id)sender
{
self.email = #"email#email.com";
self.rawPassword = #"pass";
if(self.isValid)
{
// go to next page
}
else
{
// else refresh current page
}
}
You can refer to same object within its scope using self keyword. It's similar to this keyword used in C++
I'm not sure which methods you are trying to call within the object but to call a method in the current object you use self.
i.e.
[self runSomeFunction];
Use
Note:- If you are creating a button actiion in same class then there is no need to create an instance of same class , you can use self
- (IBAction)btnSubmit:(id)sender {
// get values of email and password
// do an isvalid to check with web service.
User *user = [[User alloc] init];//not need if its same user class
user.email = #"email#email.com";//self.email=#"email#email.com"; if same user class
user.rawPassword = #"pass";//self.rawPassword=#"pass"; if same user class
if([self isValid]){//made a change here as in objective c its a syntax to call a method not with "."
// go to next page
}
else{
// else refresh current page
}
}
That depens on whether you really need to alloc a new instance which we cannt say because that depends on your business logic.
If you would crate a new instance in c++ here with new, then yes, alloc/init a new instance and use it.
If you would refer to this in c++, as your questiont title suggests, then you can use self quite corresponding to this. self.isValid and [self isValid] are equivalents.
This is for instance methods. Within class methods self would refer to the class, not the instance
Related
First - I know private frameworks/APIs won't get me to the AppStore, this is for private use/research only.
So as for the research purpose I chose MFMessageComposer I want to disable the editing of any inputs both of which are being passed from the code.
I tried to put my hands on this and I coded in the following manner . What I did is I took the path of the private framework and accessed a particular class called as CKSMSComposeController which have the above mentioned methods . I referred the class dump classes of the ChatKit.framework https://github.com/nst/iOS-Runtime-Headers/blob/master/PrivateFrameworks/ChatKit.framework/CKSMSComposeController.h
I am getting the logs of NSLog(#"Result %#", success ? #"YES" : #"NO"); as YES but still I am unable to disable the edit of recepients even after passing NO to the selector above
Can someone tell am I passing the parameter in a correct way ? Because -(void)setCanEditRecipients:(BOOL)arg1;` which is a method in the private framework accepts bool as parameter and I am passing NO in above code
This is just for internal research on private frameworks. Where I am doing wrong ?.Please tell
Class methods start with + and instance methods start with - in Objective-C.
// Following is an instance method because it starts with `-`
- (void)setCanEditRecipients:(bool)arg1;
Above method will NOT work with following code.
Class CKSMSComposeController = NSClassFromString(#"CKSMSComposeController");
SEL sel = NSSelectorFromString(#"setCanEditRecipients:");
// `CKSMSComposeController` is a class - NOT an instance
if ([CKSMSComposeController respondsToSelector:sel]) {
// will not enter if's body
}
On top of all this - you shouldn't create an instance of your own and do customizations on that. You should do the customizations on the instance that's presented by the system on screen.
Here's how you can try that -
- (void) showMessageComposeViewController {
if ([MFMessageComposeViewController canSendText]) {
MFMessageComposeViewController* messageController = [[MFMessageComposeViewController alloc] init];
messageController.recipients = #[#"555-555-5555"];
messageController.body = #"Example message";
[self presentViewController:messageController animated:YES completion:^{
// Allow enough time for the UI to be loaded fully
dispatch_after(1, dispatch_get_main_queue(), ^{
// Since `MFMessageComposeViewController` is a `UINavigationController`, we can access it's first view controller like this
UIViewController* targetVC = messageController.viewControllers.firstObject;
// Check if the instance is of correct class type
if ([targetVC isKindOfClass:NSClassFromString(#"CKSMSComposeController")]) {
SEL sel1 = NSSelectorFromString(#"setCanEditRecipients:");
if ([targetVC respondsToSelector:sel1]) {
// put breakpoint here to check whether this line is executed
[targetVC performSelector:sel1 withObject:#NO];
}
SEL sel2 = NSSelectorFromString(#"setTextEntryContentsVisible:");
if ([targetVC respondsToSelector:sel2]) {
// put breakpoint here to check whether this line is executed
[targetVC performSelector:sel2 withObject:#NO];
}
}
});
}];
}
}
I've a class of UI Test with many methods of test and when run the first test I need to do login on my app and the following methods I don't need because the test doesn't reinstall the app.
So, I tried to create a variable boolean on my class but at the begging of each test the var is recreated.
I know that the tests is running by alphabetical order but I think it's not a good way to do, I want to make sure that my second test is running and the third and etc...
Anyone knows how to help me?
In your UItestFile, create a property loggedIn
#interface UITests()
#property (nonatomic,assign) BOOL loggedIn; //use this to know wether user is logged in or not
#end
-(void)testLogin
{ if //user logged set the loggedIn flag and skip the test
{ self.loggedIn = YES;
return;
}
else
//perform login and test login flow
}
Tests does not necessarily run in alphabetical order, to change order of test you can use testInvocation and always call testLogin first.
+ (NSArray <NSInvocation *> *)testInvocations
{
NSArray *testNames = #[#"testLogin",
#"testY",
#"testB",
#"testC",
#"testA",
];
NSMutableArray *result = [NSMutableArray array];
for (NSString *testName in testNames)
{
SEL selector = NSSelectorFromString(testName);
NSMethodSignature *methodSignature = [self instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.selector = selector;
[result addObject:invocation];
}
return result;
}
I'm working on an iPhone app and facing some troubles with my shared singleton class.
I'm using a shared singleton to store two variables
int gameRuns and int totalScore
'gamRuns' just increments every time the user loads the app, and 'totalScore' is obvious :D
the issue is as follows, I load the singleton and init using my own method when the app loads using this code:
+ (SingletonLevelState*)sharedLevelStateInstance {
static SingletonLevelState *sharedLevelStateInstance;
#synchronized(self) {
if(!sharedLevelStateInstance) {
//Init a singleton
sharedLevelStateInstance = [[SingletonLevelState alloc] init];
sharedLevelStateInstance->gameRuns = 1;
sharedLevelStateInstance->totalScore = 0;
}
}
return sharedLevelStateInstance;
}
This is working great as I can reference this class from any other class and always get a pointer to the same object, so this works fine from other objects:
sharedLevelState = [SingletonLevelState sharedLevelStateInstance];
sharedLevelStateInstance.gameRuns++;
Now I added the NSCoder protocol, and added the two methods initWithCoder and encodeWithCoder as follows :
- (void) encodeWithCoder: (NSCoder *)coder
{
//encode level data
[coder encodeInt:self->gameRuns forKey:#"gameRuns"];
[coder encodeInt:self->totalScore forKey:#"totalScore"];
}
- (id) initWithCoder: (NSCoder *) coder
{
if(self = [super init]){
self->gameRuns = [coder decodeIntForKey:#"gameRuns"];
self->totalScore = [coder decodeIntForKey:#"totalScore"];
}
return self;
}
Now when the app loads, I check to see if we already have a saved sate, if it exists, I just unarchive the class with that file, if not, I init that class using my custom method above, then set its defaults, encode it to file so we have a saved state, here's the code:
//Load Level state
sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];
//Check if file is saved
NSFileManager *fm = [[NSFileManager alloc] init];
NSString *gameStatePath = [NSString stringWithString:[self getSavePath]];
if([fm fileExistsAtPath:gameStatePath]){
[self loadState];
sharedLevelStateInstance.gameRuns = sharedLevelStateInstance.gameRuns+1;
NSLog(#"Loaded %d times", [sharedLevelStateInstance gameRuns]);
}
[fm release];
Now the last line in the if statement works perfectly, it increments every time I load the app as expected and I feel really happy lol.
However, the problem arises when I try to get a reference of the singleton in another class by doing the following:
sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];
NSLog(#"Played: %d times", sharedLevelStateInstance.gameRuns);
It always counts back to 1, I know what happens but I'm not sue what's the best way to solve it, when I initWithCoder the singleton, It's not returning a static object, it creates a new one, when I init my sharedLevelStateInstance, it calls my first custom method, initializing it to the defaults hardcoded.
So StackOverflow, can you please help me ?!
I just need to know what's the best way to get a reference to the same object without allocating a new one every time I initWithCoder !
Thanks :)
So, you code should probably look like this:
if(self = [[SingletonLevelState sharedLevelStateInstance] retain])
Which sets the variables of the singleton, and returns the singleton. Be sure to retain the singleton, so that when the NSCoder releases this instance, it doesn't fully deallocate your singleton.
I'm new to objective-c and I searched and read several posts here on how to create "global variable" but I just can't get it to work right, so far I can create it and check it but the values are not persisting on another views, my global var is an array of a custom object called "profile", I would like to be able to read and write that array from any view of my iphone app (tabbarapplication delegate);
Helper.h
#interface Helper : NSObject {
int globalInteger;
NSMutableArray *profiles;
}
#property (nonatomic, retain) NSMutableArray *profiles;
// message from which our instance is obtained
+ (Helper *)sharedInstance;
Helper.m
#import "Helper.h"
#implementation Helper
#synthesize profiles, globalInteger;
+ (Helper *)sharedInstance
{
// the instance of this class is stored here
static Helper *myInstance = nil;
// check to see if an instance already exists
if (nil == myInstance) {
myInstance = [[[self class] alloc] init];
// initialize variables here
}
// return the instance of this class
return myInstance;
}
ACertainViewController.m
//Initialize Policies Array
NSMutableArray *profs = [[Helper instance] profiles];
profs = [[NSMutableArray alloc] init];
//Sample Data
Profile *prof1 = [[Profile alloc] init];
prof1.name = #"John";
//add
[profs addObject:prof1];
[[[Helper instance] profiles] addObject:prof1];
After this point if I check the global var "profiles" contents again it returns count == 0;
As of the globalInteger var I don't even know how to set its value to be able to read somewhere else in the app.
Any help is much appreciated!
Thanks!!!
You need to move "static Helper *myInstance = nil" outside the class method. Now, you're setting it to nil each time and so each time you access the sharedInstance it gets reallocated.
Declare your NSMutableArray in your AppDelegate (i.e. MyAppDelegate) class. Then from another class (like your view controller), you can do this:
#import "MyAppDelegate.h"
MyAppDelegate *aDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
aDelegate.profiles = .... // or do whatever you need to do with the profiles property.
hope that helps.
You need to alloc/initialize the profiles array. try this:
// the instance of this class is stored here: thanks #onnoweb for pointing this out
static Helper *myInstance = nil;
+ (Helper *)sharedInstance
{
// check to see if an instance already exists
if (nil == myInstance) {
myInstance = [[[self class] alloc] init];
// initialize variables here
profiles=[[NSMutableArray alloc] init];
}
// return the instance of this class
return myInstance;
}
Also take a look here: http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
"instance variable 'profiles' accessed in class method"
Where the code you posted has the comment // initialize variables here, are you actually accessing the variable profiles? Instead use myInstance.profiles.
"warning: incomplete implementation of class 'Helper' warning: method definition for '+instance' not found"
There some code you're not showing us, or the code you posted is different from your real code. There is no method declared or defined in the code you posted called 'instance', but you are attempting to call a method called 'instance'. There is one by a different name called 'sharedInstance'. Most likely in your real code you mixed up the names and declared 'instance' but defined 'sharedInstance'. Pick one name and stick with it.
I'm pretty new to OOP in general and just really started working with Obj-c a few months back. So, please be gentle! I appreciate your help in advance. Now to the question!
I have 3 Text Fields where a user inputs name, phone, and email.
I collect and place them in a label using an NSString like this [this is the one for the name]:
- (IBAction)changeGreeting:(id)sender {
self.name = textInput.text;
NSString *nameString = name;
if([nameString length] == 0) {
nameString = #"I Forgot";
}
NSString *greeting = [[NSString alloc]
initWithFormat:#"Hello, my name is %#! Really!", nameString];
label.text = greeting;
[greeting release];
}
With this I have been able to place the text from text.input into my label (as stated in label.text = greeting;)
I have another view where I'd like to have someone review this information (view a label too). I need to have access to name or Textinput.text in that other view.
How can I accomplish this?
If you don't need to communicate changes between the two view controllers, you may want to pass it in using a custom init method. This may be best for a confirmation screen, where the prompt would make no sense without this string.
- (id)initWithFrame:(CGRect)aRect username:(NSString*)aName {
if((self = [super initWithFrame:aRect])) {
_myName = [aName retain];
}
return self
}
Another option is to implement a method on the first view controller and call it from the second.
- (NSString*)enteredUsername {
return _myName;
}