Display different iphone views depending on logged in status - iphone

I want to display a login view to my users if they are not logged in and the main view if they are.
In my header file I define a variable to hold the logged in status
#define loggedIn 0
I figure I should then reference this in the initWithNibName method and then decide which nib to load.
Is the right way of doing it?
If so can someone help me out with the exact code?
Thanks for any help

I don't think you understand how to use define directives.
All this line...
#define loggedIn 0
... does it cause the compiler to substitute a zero everywhere in the code that the text "loggedIn" appears.
So, if you have code that says:
if (loggedIn) {
//... load one nib
}else{
// .... load another nib
}
The compiler turns that into:
if (0) {
//... load one nib
}else{
// .... load another nib
}
In this case, zero will evalute to false and the second nib will always be loaded.
These types of defines are only used in this way in development so you can force the app into a specific state. For example, if you wanted to test the second nib repeatedly you would define "loggedIn" to zero and if you wanted to test the first you would define "loggedIN" as 1.
What you need to do is to do a test of some kind to see if the user is logged in. I don't know what that test would be as it varies on what your logging into. Then depending on the results of that test, you would load one nib or the other.
The define directive wouldn't have anything to do with it.

#define is not what you want, as explained by TechZen.
You should rather use an int or a BOOL to do this.
For example:
BOOL loggedIn = NO;
- (void) login {
// Check login details, if correct continue, if not, break.
BOOL loggedIn = YES
}
Then you could use that in another function;
if (loggedIn == YES) {
NSLog(#"Logged in!");
// Load nib
}

Related

Using shouldPerformSegueWithIdentifier( ) method in Swift

I am trying to use swift's shouldPerformSegueWithIdentifier() method, but it accepts 2 arguments. These are (identifier: String!, sender:AnyObject)
My main goal is to execute the code when pressing a login button in my storyboard, and depending of a series of checks return TRUE or FALSE, depending if whether the correct username and password were provided. So here are my questions:
What am I supposed to use as the identifier? Apple's documentation it explains that the identifier is a string that identifies the triggered segue. So suppose that my segue had the name of loginSegueProcess. How could I use it in my ViewController tat is assigned to my UIView? The thing is that I declare the method in my code and it requires me to specify both arguments (identifier & sender). How could I provide the arguments?
Will this method actually fulfill my needs? By that I mean if it will indeed stop the segue transition whenever my Login button is clicked and depending on whether the correct credentials were provided it is going to take you to the next View or it will show, say for example, an AlertView.
Finally, I was thinking that the performSegueWithIdentifier(args) method would help me as well. Does anybody know the difference between them?
Thanks a lot in advance!
isn't it what you want to do?
override func shouldPerformSegueWithIdentifier(identifier: String!, sender: AnyObject!) -> Bool {
if identifier == "LoginSuccessSegue" { // you define it in the storyboard (click on the segue, then Attributes' inspector > Identifier
var segueShouldOccur = /** do whatever you need to set this var to true or false */
if !segueShouldOccur {
println("*** NOPE, segue wont occur")
return false
}
else {
println("*** YEP, segue will occur")
}
}
// by default, transition
return true
}
You may not invoke shouldPerformSegueWithIdentifier() method by yourself. It will be automatically called just before transition to the next view giving a chance to determine wether the transition should take place or. You may conditionally return YES/NO from this method. If your condition does't involve any sever call,a simple logical checking this method will be enough for you.
performSegueWithIdentifier() is used to invoke a segue programmatically. Consider the above case with a network call, you may return NO from shouldPerformSegueWithIdentifier() initially since authentication is going on. After getting the response from server if it success you can call the segue to execute with performSegueWithIdentifier (Here the identifier is the ID you have given in the storyboard). Before make sure you are supposed to return YES from shouldPerformSegueWithIdentifier().
Now a third case if your segue is connecting from the login button(You have to connect it from the controller itself). The checking of shouldPerformSegueWithIdentifier is no more required. You can just call the segue with performSegueWithIdentifier() after getting the success response from server

Unit test in IOS

I have a UIbutton in my app. When I click the button, it removes the last object in a NSMutableArray. For this, I want to write unit tests.Please any one give me your suggestion.
I use this code for knowing when a click on the UIButton was performed:
[viewControllerObject.backButton1 sendActionsForControlEvents:UIControlEventTouchUpInside];
Thanks,
Ricky.
At a "unit" level there are two things you're testing:
does tapping the button send the action method?
does the action method remove the last object from an array?
Ignore the first one, that's Apple's problem (or charitably it's an integration test). The second is straightforward if you think about the Assemble, Act, Assert process:
Assemble: build your view controller and its content array.
Act: call the action method.
Assert: check that the last object was removed.
-(void)testRemovalOfLastObjectOnButtonAction
{
//... build and populate the view controller
id lastObject = [array lastObject];
[viewController buttonTapped: sender];
STAssertFalse([array containsObject: lastObject], #"Object %# should be removed", lastObject);
}
Note I test explicitly whether the last object was removed, not whether the count was decremented: that could happen if any object were removed.
You can do this in several different ways. A suggestion would be to watch this great tutorial
The video explains how to unit test in UIKit.
XCode has native support for Unit Tests. If you start a new project, look for the check mark that says 'Include Unit Test'. If you use that, you will have a folder called <project_name>Tests. Open the .m file in there, and you'll see a - (void)testExample method where you can put your tests.
You can use a number of functions to test, like STAssertTrue and STAssertNotNil. Check out the Apple docs here: https://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/UnitTesting/03-Writing_Test_Case_Methods/writing_tests.html#//apple_ref/doc/uid/TP40002143-CH4-SW1
In your case, you could probably do something like this:
NSInteger arrayCount = mArray.count;
[yourInstance performButtonAction];
STAssertEquals(arrayCount -1, mArray.count);

Core data edit function

I already have a tableView with data in it. IF you tap a cell/row it pushes to an edit type of view. Is there anyway to edit core data's data other than: By edit, i mean i already have data inserted into my context. I have loaded my data into my view, the user can change the existing data, and re save it.
.h
//Below is the entity/entity's class name 'Amm'
Amm *amm;
.m
-(IBAction)save
{
[self.amm setValue:self.nameField.text forKey:#"name"];
[self.amm setValue:self.nicknameField.text forKey:#"nickname"];
[self.navigationController popViewControllerAnimated:YES];
NSError *error;
if (![self.managedObjectContext save:&error]) {
//Handle Error
}
}
I want this code to work, however the design pattern of my app isnt allowing this code to work for me as it does in other parts of my app. Thank you very much for any and all help!
I assume from what you've said you have:
A table view listing your managed objects
A view where you can edit the values of a managed object
A save button bound to the save method
What's the actual issue? I'm assuming when you tap save that:
The values in self.nameField.text isn't setting self.amm.name
The values in self.nicknameField.text isn't setting self.amm.nickname
Is that right? If so perhaps try the following code to set the managed object values:
self.amm.name = self.nameField.text
self.amm.nickname = self.nicknameField.text
If that's not the issue and you are actually setting the managed object values properly, is it that you just need to refresh the table-view? Perhaps use some NSLog commands to log every step of the applications progress.

Is there a way to invalidate NSBundle localization cache, withour restarting application? [iOS]

Let's assume that we can change in runtime Localizable.strings, that is placed in NSBundle
At the current moment, even if we change it's contents, NSLocalizedString would return old(cached) values.
Run Application
Get LocalizableString for specific key1 <- value1
Change Localizable.strings key1 = value2
<-- Do something in application to invalidate Localization cache -->
Check if LocalizableString for specific key1 == value2
What I've already tried:
[[NSBundble mainBundle] invalidateResourceCache]
[UIApplication _performMemoryWarning]
Tried to see, if there's some dictionaries. used for caching, in ivars in NSBundle.
Tried to see, in GNUStep implementation of NSBundle, but it's different from that we have in ios 6.0
What I cannot do (by definition):
- I cannot swizzle [NSBundle localizableStringForKey:value:table]
- I cannot change macroses
- In general, I cannot affect Any Original Project code, only add something at step #4
This is only for development purposes only. So, I don't need to publish it in AppStore or something, so any private methods, or solutions are OK.
So, the question is. May be someone know the way to do it, or someone who give me another ideas how to do it? Thank you.
NOTE: This solution uses private APIs and your app submissions to the App Store will be rejected if you use this code.
So, after some search I've found link that helped me
How to remove NSBundle cache
// First, we declare the function. Making it weak-linked
// ensures the preference pane won't crash if the function
// is removed from in a future version of Mac OS X.
extern void _CFBundleFlushBundleCaches(CFBundleRef bundle)
__attribute__((weak_import));
BOOL FlushBundleCache(NSBundle *prefBundle) {
// Before calling the function, we need to check if it exists
// since it was weak-linked.
if (_CFBundleFlushBundleCaches != NULL) {
NSLog(#"Flushing bundle cache with _CFBundleFlushBundleCaches");
CFBundleRef cfBundle =
CFBundleCreate(nil, (CFURLRef)[prefBundle bundleURL]);
_CFBundleFlushBundleCaches(cfBundle);
CFRelease(cfBundle);
return YES; // Success
}
return NO; // Not available
}
After flushing bundle cache, new localizations keys are used.
So now I don't need to restart my application in simulator in order to see changes in localizable strings.
You can use the uncache solution.
use Localizable.nocache.strings in your lproj folders.
e.g. example.bundle/Resources/de.lproj/Localizable.nocache.strings
loading localized strings after getting url via FileManager.
func localizedString(key: String) -> String {
let bundle = Bundle(url: bundleUrl)
return bundle.localizedString(forKey: key, value: nil, table: "Localizable.nocache")
}

Building a data driven UI

I have searched throughout SO on this topic for iPhone and everything points to the WWDC 2010 coverage, so yes I'm aware of that. But can anyone point me to a more detailed resource from where I can learn how to build a robust system for presenting different user interfaces on an app depending on the data that I'm presenting? I am fetching the data in a JSON format and my UI needs to vary depending on what I get out of the JSON parser.
Any books or online resources that give a detailed look into this topic?
Thanks!
I recently had the same issue in one of my apps (navigation style) and the way I solved it is fairly simple.
I had a user_type flag in my JSON response, and depending on that flag I would push a different view controller.
For example, given my JSON response is stored in a NSMutableDictionary called "response"
if ([response objectForKey:#"account_type"] == 1) {
/*
initialize user_type 1 viewController
*/
[self.navigationController pushViewController:userType1ViewController animated:YES];
else if ([response objectForKey:#"account_type"] == 2) {
/*
initialize user_type 2 viewController
*/
[self.navigationController pushViewController:userType2ViewController animated:YES];
}
You can have as many different user_types as you want.
Editing after clarification in comments
You will likely be manually drawing these views.
I would subclass UIView for each of the different question types you have listed (including properties for common elements like question title, choices, etc). Assuming that questions with the same question type will have the same layout.
Then you can cycle through your JSON response (once it's in an array or dictionary) and lay it out.
If it's a multiple choice question, make a new multipleChoiceQuestion view, add its properties, then addSubview to the main feed view. Then, for your next view, you will need to set the frame to be:
nextQuestion.frame = CGRectMake(0, 0 + firstQuestion.frame.size.height, height, width);
This will ensure that your second question is drawn right below the first question.