If we Tap any Profile Picture it will lead to their Profile View. Even in same view if user taps Other's Profile Pic like in Followers list, then it should lead to their profile View.But the View controller is same.Just Same functionalities as Facebook and Twitter. I need to implement this Functionality. But I don't know how can I achieve this process. Using same profile UIViewController for multiple Users.
Or is there any other way to achieve this Functionality ? Please guide me how can I achieve this Process.
For Example : VC1 is myprofileVC and VC2 is friendsProfileVC. i'm selecting friend's Pic in myprofileVC(VC1) and loadingData in friendsProfileVC(VC2).then if i select another person's ProfilePic in friendsProfileVC(VC2) means where it should lead ? or what to do ? How to Loaded that Newly Selected Person's ProfileView?In Same (VC2) or ? in this place only im getting confused !!
Ref Image :
Suppose we have 2 viewControllers, the first one is class FriendViewController and other is class UserViewController.
Step 1
We are at UserViewController. When you tap an image of a
specified user you check your id with the id that the user has.
Step 2
Depending on user id, if the user id is the same as yours, you tapped your image, so you don't have to go to another viewController, so just reload your data for any update.
Step 3
Else is user id is different, we are dealing with another user, so we have to go to another FriendViewController. Example doing that:
FriendViewController *fc = [[FriendViewController alloc]init];
[self.storyboard instantiateViewControllerWithIdentifier:#"friendvcID"];
fc.stuff = stuff;
[self.navigationController pushViewController:fc animated:YES];
Step 4
Now we are at FriendViewController and if depending on a image we tap, if we have it as the same as our id, we are navigating to our profile, so what we do is check if we already have it to our navigationStack, if we don't we need to push.
//Check if we have userProfile on navigationStack
if ([self hasUserProfileOnStack]!=-1)
{
//We have it on specific index, so we are popping to that viewController, which is UserViewController
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:[self hasUserProfileOnStack]] animated:YES];
}
else
{
//We dont have it in navigationStack so we are pushing it
UserViewController *fc = [[UserViewController alloc]init];
[self.storyboard instantiateViewControllerWithIdentifier:#"uservcID"];
fc.stuff = stuff;
[self.navigationController pushViewController:fc animated:YES];
}
//Method which helps us to find if we have it to navigationStack by returning the index on navigationControllers
-(NSInteger)hasUserProfileOnStack
{
for (NSInteger i=0; i<[self.navigationController.viewControllers count]; i++)
{
if ([[self.navigationController.viewControllers objectAtIndex:i] isKindOfClass:[UserViewController class]]) {
return i;
}
}
return -1;
}
Step 5
If that ID is not as the same as our ID then we just have to execute Step 3
This is the info that I could give to you right now, it's a bit difficult explaining with words, but this is how I can explain it here. Hope it helps
You should start learning iOS Programming from scratch, and start developing apps step by step. There are plenty of sites and books where you can learn. I would suggest Ray Wenderlich because it has great iOS tutorials.
Referring to that question you have, I am developing a social iOS app right now where this thing is achieved by:
Using an ID for every User
I download data on a specific server by sending that ID
Passing them to the ProfileViewController properties which are
declared in .h file
Then I load these properties there where I want
Anyway I think is too early for you to achieve these things, you have to learn iOS step by step and practice will give you experience to achieve great things.
Related
Im creating a new design to my app so I have created a new story board. I need to support the older design for now, but I am designing the upcoming one on the fly. I am reusing some classes and ViewControllers. Is there a way to check the storyboard name in classes? For Example, if 'main' storyboard have the normal left bar button item, however if 'newDesign' do 'x'?
I cant find a way to get the 'UIStoryboard' name?
For example in pseudocode:
if(self.storyboard.name isEqualToString: #"Main"){
}else{
}
How about this?
UIStoryboard * storyboard1 = self.storyboard;
NSString *name=[storyboard1 valueForKey:#"name"];
NSLog(#"%#",name);
Another approach is to check the restoration ID of the view controllers. How about that?
Working on a shopping store app. I've been going in circles for the past week and a half trying to figure out how to correctly do this. The problem lies in a UILabel that needs to be dynamically updated with text that corresponds to checked checkboxes. It also needs to know whether to apply selection when apply button has been tapped or return previous selection if customer decided to change their mind and not tap apply. This is where I'm running into issue.
I refer to 3 controllers as image 1, image 2 and image 3.
My model is a separate class that I pass copies of back and forth to keep selections made by users when they wish to refine a collection of clothing item results.
So for example the user taps the refine button in image 1
They are taken to image 2 where they decide what they want to refine results by
They are then taken to image 3 page where they make the selection
Where problems begin:
In short in image 3 a customer makes a selection and taps done, they are then taken back to image two where their selection is shown in a string separated by commas in a UILabel underneath the chosen refine by option e.g. Gender. If they are ok with their selection they tap apply and the refining is done and displayed like in image 1. A tick is also shown in the refine button to make the customer aware refining is active.
Now lets say a selection has already been made like in the images below and the customer goes back to image 3 to modify a selection. Let's say he unchecked "microsites". What should happen is when he goes back to image 2 the list underneath the refine by option should be updated.
This works fine but I'm actually updating the property that is updated when the apply button is tapped. So if the customer decides they don't want to refine anymore and don't click apply but the back button instead to take them to image 1 then I need the original selection string to be updated in the property.
The thing is this very property is updated whenever a selection is made in image 3. So when the customer does return to image 2 then because we unchecked "microsites" only "men" will show in the string underneath the refine by option.
I've tried creating a temp property to hold the previous selection but thing's just really get messy with all this going back and forth.
Further info:
I pass my model class back and forth between controllers using the prepareForSegue method and delegation/protocols.
Image 2 is aware when the done button in image 3 is tapped. This is where I pass the model over. Image 1 knows when the apply button in image 2 is tapped and again this is where I pass the model over. To pass the model from image 1 to 2 then 2 to 3 I use the prepareForSegue method.
Image 1:
Image 2:
Image 3:
How would you do this? I feel I've made a good start by moving all my model into its own class. This has made things easier but the other problem with the UILabel is holding me back.
Update:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[[sender titleLabel] text] isEqualToString:#"Gender"]) {
VAGRefineGenderViewController *vc = [segue destinationViewController];
[vc setDelegate:self];
[vc setRefineModel:[self refineModel]];
}
}
Working code:
#implementation VAGRefineModel
{
VAGRefineModel *_object;
}
-(id)copyWithZone:(NSZone *)zone
{
VAGRefineModel *modelCopy = [[VAGRefineModel alloc] init];
modelCopy->_object = [_object copyWithZone: zone];
return modelCopy;
}
Then in image 2/controller 2 I just set the model being passed to controller 3 as the copy of the existing model.
This seems fairly simple.
You should indeed create a copy of the model and pass this to the next viewController then you don't have to worry about the edits made to it.
If the user presses back then that copy is just discarded.
If you press done then you receive the copy and replace your current model then reload your views.
It might look as simple as this (no error handling to make it easy to follow)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
{
Model *model = [self.model copy];
VC2 *viewController = segue.destinationViewController;
viewController.model = model;
viewController.delegate = self;
}
- (void)didTapDoneButtonWithModel:(Model *)model;
{
self.model = model;
[self reloadData];
}
I didn't read your post in detail, but did read enough to get the gist of it.
I'm gonna call your screen level 1 (master), level 2 (top level detail) and level 3 (fine detail) instead of image 1/2/3, because I'm talking about pictures, I'm talking about master/detail view controllers.
It sounds like you have 3 levels of view controllers that allow the user to edit finer levels of detail for a search.
I would suggest setting up your model so you can encapsulate the details handled by levels 2 and 3 into objects. When you get ready to drop to level 3, create a copy of the settings for gender and micro sites, and pass it to the level view controller. The user will interact with level 3, which has it's own copy of the settings.
Level 3 should set up level 2 as it's delegate, with a delegate message
-userChangedSettings: (Level3SettingsObject *) changedSettings
Or something similar.
If the clicks done, the level 3 VC would invoke that method on it's delegate, passing the changes to the Level3Settings object up to level 2, then pop itself/dismiss itself. (whichever is appropriate.)
If instead the user clicks cancel, just close pop/dismiss without calling the delegate method to tell the delegate about the change in settings. The settings in the level 2 object won't have changed.
The same would go for the communication between level 2 back up to level 1.
If it makes sense, you can make it so that the settings for level 1 contain level 2 data objects, and that the settings for level 2 contain level 3 data objects. That way changes to level 3 get passed back to level 2, and if the user cancels from level 2, all the changes made in level 2 and level 3 are discarded, and only if they tap save in level 2 do the changes from that level get passed up to level 1.
I am coding a Calorie Tracker app in which I have 3 view controllers. They are all hooked up to a tab bar controller in the storyboard.
Diet View Controller
Exercise View Controller
Home View Controller
Essentially what I want to do is to take the data from my Exercise view Controller and My Diet View Controller and display it on my Home View Controller. This is my code for viewDidLoad in my HomeViewController.m
//Referencing both view controllers
MainViewController *mainViewController = [[MainViewController alloc] init];
ExerciseViewController *exerciseViewController = [[ExerciseViewController alloc] init];
//Doing the math
int totalCalsConsumed = mainViewController.totalLabel.text.intValue;
int totalCalsBurned = exerciseViewController.totalCalsBurned.text.intValue;
int totalAmountOfCalories = totalCalsConsumed - totalCalsBurned;
//display the data
NSString *totalAmtCalsText = [NSString stringWithFormat:#"%i", totalAmountOfCalories];
totalAmtOfCals.text = totalAmtCalsText;
Also, I cannot pass any data with segues because all my view controllers are hooked up to a tab bar, and there is no prepareForSegue method for tab bars.
All help is appreciated, and I would also like to know if I DESPERATELY HAVE TO use Core Date for this dilemma. For now I'm trying to dodge Core Date for it is a very advanced topic that I will touch upon in the future, but If I MUST use Core Data for this app I'll figure something out.
Due to your strong desire to avoid Core Data - which I feel should be considered - I can provide a quick, perhaps dirty (maybe not) solution so that you can have data accessible through out your viewControllers.
Based on what youre doing it seems as though you want to access data from your tabbar view controllers.
One way of doing this is to have a data model in one single place which can be accessible by other view controllers. Like a server with a webservice or have a singleton that keeps your data in one place.
In your case, you want a quick solution, you can do this for now which works, as long as all the ViewControllers mentioned are in your tabBar
//Create variables
int totalCalsConsumed;
int totalCalsBurned;
int totalAmountOfCalories;
//All your view controllers are accessible from your tabBar like so
NSArray *myViewControllers = self.tabBarController.viewControllers;
//We iterate through the view controllers in the tabBar
for(int i = 0; i < [myViewControllers count]; i++){
//This is the current view controller in the for loop execution
id currentVC = [myViewControllers objectAtIndex:i];
//Check if the currentVC variable is of type MainViewController
if([currentVC isKindOfClass:[MainViewController class]]{
//lets access the totalLabel property and store in variable
totalCalsConsumed = ((MainViewController *)currentVC).totalLabel.text.intValue;
}
//Check if the currentVC variable is of type ExerciseViewController
else if([currentVC isKindOfClass:[ExerciseViewController class]]){
//if so lets now access the totalCalsBurned property and store in variable
totalCalsBurned = ((ExerciseViewController *)currentVC).totalCalsBurned.text.intValue;
}
}
//Doing the math
totalAmountOfCalories = totalCalsConsumed - totalCalsBurned;
//display the data
NSString *totalAmtCalsText = [NSString stringWithFormat:#"%d", totalAmountOfCalories];
totalAmtOfCals.text = totalAmtCalsText;
I haven't tested this as I just wrote this now, but it should be good from the get go. Code commenting is there for you understand whats going on. Pretty straight forward.
tip for you mate since youre developing a fitness app
In the future, I do recommend something more persistent, where by data isnt lost if the application has quit, especially since you're creating a fitness app. I currently am using the BodyBuilding fitness app in my personal time, and have been frustrated at times when data was lost during my work out (sets information, exercises done with total reps for each set) only because the developers never bothered to store my data somewhere whilst I was doing my exercise, in case for when my battery died out.
You could choose 1 of several approaches:
You could create a Singleton and store/read all persistent data from this singleton. Singletons should be used with care though.
You could use NSNotificationCenter to send out NSNotifications whenever some value changes. UIViewControllers can register to receive NSNotifications.
You could store persistent data on the file system using CoreData or some other technology like NSUserDefaults or NSKeyedArchiver / NSKeyedUnarchiver.
Perhaps a dependency injection method could be used as well. Creating an object in the app delegate and passing it to all related UIViewControllers. Use this object in the same way you'd use the singleton I mentioned as option 1.
There's probably more options that I can't remember at this current moment.
Key value Coding , NSNotificationCentre and Delegates are preferred. But NSNotificationCentre is easiest in your case.
The UIViewController Home View Controller must add observer like this : Init :
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(methodToUpdate:) name:#"UPDATE_ME" object:(id)anyObject];
In delloc method :
[[NSNotificationCenter defaultCenter] removeObserver:self];
Post it from other 2 classes like on any UIButton action:
[[NSNotificationCenter defaultCenter] postNotificationName:#"UPDATE_ME" object:(id)anyObject];
Advantage of NSNotificationCentre is that they can add observers in multiple classes ..
I have searched for an entire day for a simple example on this and haven't found it yet. I am working on an app and I want to make an API call on the initial load and populate some variables that will be accessible in any of the tab views.
Example: I want to make a single API call to get my data which will include data relating to alerts for the alerts tab. I want to use this data on the initial load to update the "Alerts" tab badge. However, I want to also use that information on the alerts page once the person goes to that tab without having to make another API call to get the same information again.
I have read a ton of explanations that do not fit my requirements, so I am looking for a good example to help me out.
Use your UITabBarViewController's viewControllers property to access the array of view controllers in your tab bar controller. Typecast them according to your architecture of tab bar controller.
Then get a pointer to any of view controller using that array.
For example, say your tab bar controller has 5 tabs, each tab having a UINavigationController which has particular UIViewController as root view controllers. Say you want to set badge value of 3rd tab to your web response array count. You can do that as
[[[self.tabviewController viewControllers] objectAtIndex:2]
setBadgeValue:[NSString stringWithFormat:#"%d",[myArray count]];
You can also get to particular view controller's property by typecasting the view controllers. For example
MyViewController *myVc = (MyViewController*) [[(UINavigationController*)[[self.tabviewController viewControllers] objectAtIndex:2] viewControllers] objectAtIndex:0];
[myVc setPropertyName:propertyValue];
I had this question typed up since yesterday and made sure to search before posting. There was no question similar that I found that had the answer, and it may be very straight forward or maybe this is not the way to do it but here is how I solved this issue: using NSUserDefaults and the code example on this page
Put the data in your app delegate object. You can access it from anywhere in your app by (MyAppDelegate *)[[UIApplication sharedApplication] delegate], or you can give each of your view controllers an explicit link to it.
NSUserDefaults isn't really meant for sharing data globally in your app, although it would get the job done. It also has the benefit that the information sticks around if your app can't connect to the server next time. Is that a good thing or a bad thing?
Put all of those variables in a single class and access a shared instance of it whenever you want.
Add
+ (YourClass *)sharedObject
{
static YourClass *sharedClassObject = nil;
if (sharedClassObject == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedClassObject = [[YourClass alloc] init];
//Initialise it here if necessary
});
}
return sharedClassObject;
}
To access the shared instance, simply use [YourClass sharedObject].
You should use NSNotificationCenter to post the notification that new data arrived and your new data as an object.
Each of the viewControllers that need that object should just subscribe to that notification and just consume the new data.
This may be impossible, but I'm trying to save the state of my application between scene transitions, but I can't figure out what to do. Currently I love the way that when you have an application running and hit the home button, you can go back to that application just where you left off, but if you transition between scenes (in a storyboard), once you get back to that scene the application state was not saved.
I only have two different scenes that need to be saved (you transition back and forth from one to the other). How can I go about saving a storyboard scenes state without taking up precise memory?
More Detailed: Here is my entire storyboard. You transition back and forth between scenes using the plus toolbar button. On the second scene the user can tap on the table view cells and a real image will fill the image view (See figure 1.2)
Figure 1.1
In figure 1.2 you see what happens when you tap inside one of the many table view cells (an image view pops up.)
Figure 1.2
THE PROBLEM: When you tap a table view cell, which fills an image view (shown in figure 1.2) it works fine if you stay on that scene or even hit the iPhone home button (if you hit the iPhone home button and then reopen the app the scene's state was saved and the image view filled with a simple image still shows just like we left it), but if I transition (using the plus button) back to the first scene, and then use the plus button on the first scene to get back to the second scene the image view that I created (shown in figure 1.2) disappears and the second scene loads without saving the state and image views we filled.
EDIT: I tried using the same view controller for both scenes, but it didn't solve the problem.
UPDATE: I just found the following code (that I think stores a views state). How could I use this and is this what I've been looking for?
MyViewController *myViewController=[MyViewController alloc] initWithNibName:#"myView" bundle:nil];
[[self navigationController] pushViewController:myViewController animated:YES];
[myViewController release];
I would suggest a combination of two things:
1. Take DBD's advice and make sure that you don't continuously create new views
2. Create a shared class that is the data controller (for the golfers, so that the data is independent of the scene)
The correct way to make the segues would be to have one leading from the view controller on the left to the one on the right. However, to dismiss the one on the right you can use
-(IBAction)buttonPushed:(id)sender
[self dismissModalViewControllerAnimated:YES];
}
This will take you back the the view controller on the left, with the view controller on the left in its original state. The problem now is how to save the data on the right.
To do this, you can create a singleton class. Singleton classes have only one instance, so no matter how many times you go to the view controller on the right, the data will always be the same.
Singleton Class Implementation (Of a class called DataManager) - Header
#interface DataManager : NSObject {
}
+(id)initializeData;
-(id)init;
#end
Singleton Class Implementation (Of a class called DataManager) - Main
static DataManager *sharedDataManager = nil;
#implementation DataManager
+(id)initializeData {
#synchronized(self) {
if (sharedDataManager == nil)
sharedDataManager = [[self alloc] init];
}
return sharedDataManager;
}
-(id)init {
if(self == [super init]) {
}
return self;
}
#end
Then, inside your view controller code you can grab this instance like this
DataManager *sharedDataManager = [DataManager initializeDataManager];
This way you will have the same data no matter how many times you switch views.
Also, you can better adhere to MVC programming by keeping you data and your view controllers separate. (http://en.wikipedia.org/wiki/Model–view–controller)
Figure 1.1 has a fundamental flaw which I believe the basis of your problem.
Segues (the arrows between controllers on the storyboard) create new versions of the UIViewControllers. You have circular segues. So when you go "back" to the original screen through the segue is really taking you forward by creating a new version.
This can create a major problem for memory usage, but it also means you can't maintain state because each newly created item is an empty slate.
Since your are using a UINavigationController and pushViewController:animated: you should "pop" your controller to get rid of it.
On your "second" scene, remove the segue from the + button and create an IBAction on a touchUpInside event. In the IBAction code add the "pop"
- (IBAction)plusButtonTapped {
[self.navigationController popViewControllerAnimated:YES];
}
I see what you mean. This should happen to every application, as when the last view controller in the navigation stack is transitioned away from, it is deallocated and freed. If you need to save values such as text or object positions, a plist may be the way to go. See this related question for how to use a plist.
Apple isn't going to do this for you. You should probably just save the state of each view using NSUserDefaults and each time your application launches re-load your saved data.
If you are storing everything in CoreData you would only need to save the active view and a few object ids, if not you would need to save any data you have.
Don't expect iOS to save anything that you have in memory between launches. Just store it in NSUserDefaults and load it each time.
Store the state of the scene in NSUserDefaults or inside a plist file then when loading up the scene just load it with the settings from there. If the images are loaded from the internet you might also want to save them locally on your iphones hard drive so it runs a bit smoother.
I don't think you should cycle the segues, just use one that connects viewcontroller 1 from viewcontroller 2 should be enough and that way you make sure that no additional viewcontrollers are being made (memory problems maybe?)
However for your particular problem, I believe that you should use core data to save the exact state of your table, view because ios doesn't save the exact state of view at all times. it will require work but you will achieve what you want. You will need to save the exact photo( using a code or enums that will be saved), the location in the table view, the score or well whatever data you need to save that state.
The best of all is that coredata is so efficient that reloading the data when the app is relaucnhed or into foreground it takes no time, and ive used core data to load more than 5k of records until now and works just fine and its not slow at all.
When i get back home ill provide a code you might use to get an idea of what i mean.
The key here is to:
Have some sort of storage for the data that your application needs. This is your application's data model.
Give each view controller access to the model, or at least to the part of the model that it needs to do its job. The view controller can then use the data from the model to configure itself when it's created, or when the view is about to appear.
Have each view controller update the model at appropriate times, such as when the view is about to disappear, or even every time the user makes a change.
There are a lot of ways that you can organize your data in memory, and there are a lot of ways that you can store it on disk (that is, in long term storage). Property lists, Core Data, plain old data files, and keyed archives are all possibilities for writing the data to a file. NSArray, NSDictionary, NSSet, and so on are all classes that you can use to help you organize your data in memory. None of that has anything to do with making your view controllers feel persistent, though. You'll use them, sure, but which one you choose really doesn't matter as far as updating your view controllers goes. The important thing, again, is that you have some sort of model, and that your view controllers have access to it.
Typically, the app delegate sets up the model and then passes it along to the view controllers as necessary.
Something else that may help is that you don't have to let your view controller(s) be deleted when they're popped off the navigation stack. You can set up both view controllers in your app delegate, if you want, so that they stick around. You can then use the ones you've got instead of creating new ones all the time, and in so doing you'll automatically get some degree of persistence.