Setting UImageView and UILabel based on user - ios

I have a registration for a user in my app. When the user registers they are redirected to a home ViewContoller. I am just wondering how i can set the UIImageView and a label on the home ViewController to the data that the user used when registering. I also am wondering how i can also achieve this when the user logs into the app. Any suggestions would be great:)

First you need what is called a data model in software engineering. It contains the basic data structures your app should work with.
In your case, the data model would probably contain a class User. This User class should have properties. In your case probably the class would probably look somewhat like that:
#interface User : NSObject
#property (strong, nonatomic) NSString *userId;
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) UIImage *image;
#end
Then in the viewDidLoad of your view controller, you need to set the labels which you e.g. can declare as IBOutlet from Interface Builder, this will look somewhat like that:
- (void)viewDidLoad
{
[super viewDidLoad];
self.nameLabel = self.user.name; // nameLabel is a UILabel
self.userIcon.image = self.user.image; // userIcon is a UIImageView
}
Hope it helps.

Related

Abstract Factory method pattern

I have gone through couple of video and blog tuts online. Felt like i understood everything, however still struggling to implement the Abstract factory pattern. Here is my requirement:
I have a User class which should give a user object.
There are two types of users in my application for e.g Service Provider (Provider) and Service receiver (Consumer).
There are some common properties between these two types of users like name, email id , mobile number etc. For Provider type there will be some extra properties.
Provider types could be of for e.g. TaxiDriver or Restaurant etc.
I want to implement Abstract factory and factory method pattern for this user class so that the application can be decoupled from the User model and whenever the application wants an User of type Provider or Consumer it should get the right object.
What I tried so far:
AbstracUserProtocol.h
#protocol AbstractUserProtocol
#required
#property(nonatomic, strong) id delegate;
#property(nonatomic, readonly, getter=isExist) BOOL exist;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *emailID;
#property (nonatomic, assign) NSInteger phoneNumber;
-(void)saveUserData;
-(void)retrievUserData;
#end
AbstractUser.h
#interface AbstractUser : NSObject <AbstractUserProtocol>
-(id)initWithType:(UserType)usrType;
#end
AbstractUser.m
#implementation AbstractUser
#synthesize delegate, exist, name, emailID, phoneNumber;
-(id)initWithType:(UserType)usrType
{
self = nil;
if (usrType == kConsumer) {
self = [Consumer alloc]init];
}
else if (usrType == kProvider) {
self = [ProviderFactory alloc] initWithServiceType:TaxiService];
}
return self;
}
-(void)saveUserData {
[NSException raise:NSInternalInconsistencyException
format:#"You have not implemented %# in %#",
NSStringFromSelector(_cmd), NSStringFromClass([self class])];
}
-(void)retrievUserData {
}
#end
Now created two subclasses Consumer and ProviderFactory from AbstractUser class.
Consumer.h
#interface Consumer : AbstractUser
#property (nonatomic, strong) NSString *address;
#end
ProviderFactory.h
#interface ProviderFactory : AbstractUser
-(id)initWithServiceType:(ServiceType)srvType;
#property(nonatomic, strong) NSString *ownerDetails;
#end
So whenever in future if my application want to support another business user like Taxi and Restaurant type then I just have to create a class and init through ProviderFactory class.
Is my approach correct for the abstract Factory pattern? Appreciate any guidance.
Based on your follow up question, I edited the answer.
I'm not entirely sure you need to use AbstractFactory for what you are trying to accomplish. The basics of AbstractFactory is that it allows you to
provide an interface for creating families of related or dependent
objects without specifying their concrete classes (Gamma et al.)
Take this example from Design Patterns: Elements of Reusable Object-Oriented Software by Gamma et al. Let's say you are creating a toolkit to build user interfaces for a document editor. You may have a bunch of widget objects like scrollers, buttons, toolbars, etc. But you may want to later add a different look-and-feel to the document editor. So then you can use AbstractFactory to provide an interface to create all of the widget products (i.e. createScrollbar, createButtons, etc.) but then to change the look-and-feel, you subclass the abstract class and override the methods so that say, createScrollbar returns a scrollbar that has a 3-D effect. In another case, you subclass the abstract class to create a pink scrollbar. The options are endless, and since your client code doesn't care what the scrollbar looks like (all the client cares about is whether it scrolls text or not), you can easily add future looks-and-feels without touching the client code.
In your case, the client cares what kind of AbstractUser it is getting because in some cases it needs a Customer and in some cases a Provider. So either way, your client code would have to be changed if in the future you added a new kind of user.
That said, I think the best approach for you would be to just create an abstract base class of User and then subclass it and add the user-specific properties to the subclass. Here is an example of what I mean.
AbstractUser.h
#import <Foundation/Foundation.h>
#interface AbstractUser : NSObject
#property(nonatomic, strong) id delegate;
#property(nonatomic, readonly, getter=isExist) BOOL exist;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *emailID;
#property (nonatomic, assign) NSInteger phoneNumber;
#end
Consumer.h
#import "AbstractUser.h"
#interface Consumer : AbstractUser
#property (strong, nonatomic) NSString *address;
#end
ViewController.m
#import "ViewController.h"
#import "Consumer.h"
#import "Provider.h"
#interface ViewController ()
#property (strong, nonatomic) Consumer *consumer;
#property (strong, nonatomic) Provider *provider;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_consumer = [[Consumer alloc] init];
_provider = [[Provider alloc] init];
self.consumer.name = #"Jason";
self.consumer.address = #"some address";
self.provider.name = #"Stack Overflow";
#end

Access an IBOutlet from another class?

I need to access this IBOutlet's value in another class.. How would I go about doing this?
Heres my SaveTextViewController.h class
#import <UIKit/UIKit.h>
#interface SaveTextViewController : UIViewController{
IBOutlet UITextField *saveText;
}
#property (retain, nonatomic) IBOutlet UITextField *saveText;
#end
And here is my TextView.m class
#import "TextView.h"
#import "SaveTextViewController.h"
#implementation TextView
- (IBAction)saveTextView{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
//Trying to access the returned variable "saveText" from IBOutlet in SaveTextViewController
NSString *documentTXTPath = [documentsDirectory stringByAppendingPathComponent:#"%d",saveText];
NSString *savedString = self.text;
[savedString writeToFile:documentTXTPath atomically:YES];
NSLog(#"%#", documentTXTPath);
}
Thanks!
There is no clean way to just generically access the IBOutlet UITextField *saveText from any app. You can declare it in the .h file instead of the .m and have it accessible that way, assuming you can send a pointer to your SaveTextViewController class. But its a better practice to pass a pointer to your UITextFIeld to your TextView class from your SaveTextController class.
in TextView.h create a property
#interface TextView: UIView
#property (nonatomic, strong) UITextField *textField;
#end
in your SaveTextViewController.m create another property:
#interface SaveTextViewController : UIViewController{
IBOutlet UITextField *saveText;
}
#property (retain, nonatomic) TextView *textView;
#property (retain, nonatomic) IBOutlet UITextField *saveText;
assign self.textView to your TextView
in your viewDidLoad method, set the textField in your TextView class like this:
self.textView.textField = self.saveText;
That would give you a clean connection between those two classes.
An IBOutlet is just behaving like any other property or instance variable. So if you want to pass that reference to another class, just do exactly that. Note that you do not need to specify an instance variable with the same name as the property. The current runtime will handle this itself.
If you want to pass a reference to the UITextField, add a property to your text view.
#interface TextView : UIView
#property (retain, nonatomic) UITextField *saveTextField;
...
#end
In your SaveTextViewController you can now set that property. You can do this in the viewWillAppear: method for example.
#implementation SaveTextViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.textView.saveTextField = self.saveText
}
#end
Also note that if you need a reference to the TextView and you created that in your nib/storyboard, add another IBOutlet to the SaveTextViewController.
#import "TextView.h"
#interface SaveTextViewController : UIViewController
#property (retain, nonatomic) IBOutlet UITextField *saveText;
#property (retain, nonatomic) IBOutlet TextView *textView;
#end
Finally I would also recommend you to rename saveText to saveTextField, because that's what it is. Also, you seem to be using unsanitized user input data from text fields and feed them into filenames. This is generally a bad idea™. I would recommend you to think about what you are actually trying to do. This is potentially dangerous and can lead to data loss and more fun stuff.
In
#implementation TextView
type
SaveTextViewController *saveTextViewController = [[SaveTextViewController alloc] init];
NSString *documentTXTPath = [documentsDirectory stringByAppendingPathComponent:#"%d",saveTextViewController.saveText];
Hope this helps!

Should I make my ivars properties in iOS?

Just when you think you understand something, you don't! :)
I understand that if I make a variable a property, I can access it anywhere in the Class and even set it from outside that class.
I thought if I didnt need it I could just make it an ivar. So I have a viewcontroller with about 5 UILabels. So in its viewDidLoad I say:
pharmacyName.text = self.receivedLocation.name;
pharmacyTel1.text = #"556-7843";
pharmacyTel2.text = #"991-2345";
pharmacyTel3.text = #"800-0001";
When I have declared them like so in the .h file:
#interface DetailViewController : UIViewController{
IBOutlet UILabel *pharmacyName;
IBOutlet UILabel *pharmacyTel1;
IBOutlet UILabel *pharmacyTel2;
IBOutlet UILabel *pharmacyTel3;
}
#property (nonatomic,strong) MyLocation *receivedLocation;
#end
No. Its not mandatory to create ivar as property. If you don't want to access it outside of class just use as it is. In ARC you can also declare your IBOutlet as below:
#interface DetailViewController : UIViewController{
__weak IBOutlet UILabel *pharmacyName;
__weak IBOutlet UILabel *pharmacyTel1;
__weak IBOutlet UILabel *pharmacyTel2;
__weak IBOutlet UILabel *pharmacyTel3;
}
This will keep a week reference of outlets. Here is detail of __weak and strong
There are always many ways you can approach programming tasks and standards. Our group has started using a few coding standards. We like to put our instance variables that are NOT accessed from outside the class (and protocol statements) in the private interface in the .m file like this:
#interface DetailViewController() {
NSString *value_;
}
#end
We also like to use #property for our instance ivars and declare those in the private interface as well like this:
#interface DetailViewController() {
}
#property (nonatomic, strong) IBOutlet UIlabel *pharmacyName;
#end
and then in your code, you would refer to this as self.pharmacyName. It seems to work pretty well with autocomplete, and with getting and setting. Also when you have thread safety issues, the nonatomic, strong behavior comes in handy.

Which the method recommended by Apple allow me to connect the outlet in Interface Builder?

What is the technical difference between them and which is the method recommended by Apple?
// 1
#interface CocoaQuizViewController : UIViewController
{
IBOutlet UILabel *myLabel;
}
#end
// 2
#interface CocoaQuizViewController : UIViewController
{
IBOutlet UILabel *myLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
#end
// 3
#interface CocoaQuizViewController : UIViewController
{
UILabel *myLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
#end
// 4
#interface CocoaQuizViewController : UIViewController
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
#end
The default is (generated automatically if you drag and drop outlet directly from xib to source class):
#interface CocoaQuizViewController : UIViewController
#property (nonatomic, weak) IBOutlet UILabel *myLabel;
#end
All are quite OK.
With new LLVM you are supposed to do 4th one.
#interface CocoaQuizViewController : UIViewController
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
//even you use strong and weak intead of retain,assign,copy
#end
In earlier days, you were doing 1, 2 and 3. Now most of the thing is atomatcally done by the compiler. So your work is now easier than never before.
With New Compiler which comes with XCode4.4 and onwards gives you auto-synthesize for all the properties you declare. ivars also get created prefixed with your property name.
The 4th one, Because Now Apple has recommended all developers to make use of properties.
A couple of thoughts:
Your fourth example avoids a whole category of possible bugs that can plague the first three examples, where you can accidentally end up with two ivars (e.g. if you omitted the #synthesize, the compiler would generate an ivar called _myLabel, your myLabel ivar wouldn't be used, and, thus, would end up being redundant and only serve as a possible source of confusion).
If you use ARC (which I'd encourage, if you can), then clearly that retain reference becomes weak.
You probably shouldn't be "writing" the IBOutlet code yourself anyway. It's just an opportunity to introduce a bug. In IB, click on the "assistant editor" to show your code while working on IB, and then control-drag (or right-click-drag) from the control to the code, and IB will write your code for you! See https://stackoverflow.com/a/15551101/1271826 for screen snapshots.

Changing outlet object properties

I have a view controller alertForNeedsClassification as a property in another class, as such:
#interface SCAAppDelegate()
{
HomeScreenViewController * _homeScreenViewController;
NSInteger SCAStatus;
}
#property (strong, nonatomic) PromptClassifyViewController * alertForNeedsClassification;
#end
#implementation SCAAppDelegate
#synthesize alertForNeedsClassification;
#synthesize window = _window;
PromptClassifyViewController's interface looks like this:
#interface PromptClassifyViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *headerTitle;
#property (weak, nonatomic) IBOutlet UITextView *message;
#property (weak, nonatomic) IBOutlet UIButton *notNowButton;
#property (weak, nonatomic) IBOutlet UIButton *classifyButton;
#property (weak, nonatomic) IBOutlet UIImageView *backgroundImageView;
#property (weak, nonatomic) IBOutlet UIView *alertView;
#property NSUInteger tag;
#property (weak, nonatomic) IBOutlet id<PromptClassifyViewControllerDelegate> delegate;
- (void)show;
- (void)showFromView:(UIView *)view;
- (IBAction)show:(id)sender;
- (IBAction)dismiss:(id)sender;
- (IBAction)buttonWasPressed:(id)sender;
- (void)setHeaderTitleWithText:(NSString *)text;
#end
I am trying to change the values of IBOutlets message and headerTitle text, like this:
alertForNeedsClassification = [[PromptClassifyViewController alloc] initWithNibName:#"PromptClassifyViewController" bundle:nil];
//[alertForNeedsClassification setDelegate:self];
self.alertForNeedsClassification.headerTitle.text = #"A title";
alertForNeedsClassification.message.text = #"A message";
Then I show alertForNeedsClassification calling a show method (it's like a custom uialertview, but it doesn't subclass from uialertview).
Thing is, no matter how I change it, the text on alertForNeedsClassification.view is always that which is defined in the nib, ie. I can't change it programmatically.
My custom alert view is based on Jeff LaMarche's design: http://iphonedevelopment.blogspot.com/2010/05/custom-alert-views.html
Any ideas what might be going on?
Please be careful when you allocate and initialize the UIView object, especially if you trying to mix using Nib and dynamically generating objects. The best place is within -(void)awakeFromNib or -(void)viewDidLoad
Also, make sure these methods are called. By using -(id)initWithNibName:bundle: only cannot make sure your view to be loaded. Try -(void)addChildViewController and -(void)addSubview: on parentViewController's view to make sure view is loaded after being initialized.
If the text had to be prepared before being loaded, assign it to separate NSString property within PromptClassifyViewController class. Since this property is independent from view being loaded, you can change it's value BEFORE view is appeared. Make sure this text is used and applied to the headerTitle within -(void)show method.
Since you allocate PromptClassifyViewController and access weak referenced headerTitle from self. alertForNeedsClassification, make sure it's not deallocated right afterward.
Usually, weak option is not used for IBOutlet properties. Though it is used when generating outlet connection code by dragging objects from Interface Builder. Try testing your code using strong.
I was assigning values to the IBOutlets before they were alloc'd/initialized. The solution I implemented was to set the values I needed to non-IBOutlet properties (NSStrings in this case) and assign those where needed, in Prompt...Controller's viewDidLoad;

Resources