I was using this code to pass data between controllers.
InterfaceController.reloadRootControllersWithNames(["1","2","3"], contexts: ["adf","asd","asd"])
I called this code in willActivate() method, that you can see here.
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
InterfaceController.reloadRootControllersWithNames(["1","2","3"], contexts: ["adf","asd","asd"])
}
I have no idea about whats wrong with this code, in apple watch, the app is just refreshing again and again. Is there any other method to pass data between interface controllers while we use page based navigation.??
Please Find the below way of passing data in paged-based navigation in watch application (Watch os 2 and later).
Note :
An array of strings, each of which contains the name of an interface controller you want to display in the page-based interface. In your storyboard, the name of an interface controller is stored in the object’s Identifier property, which is located in the attributes inspector. The order of the strings in the array is used to set the order of the corresponding interface controllers. This parameter must not be nil or an empty array.
Objectiv C
[self presentControllerWithNames:#[#"FirstViewController",#"SecondViewController",#"ThirdViewController"] contexts:#[#"adf",#"asd",#"asd"]];
Swift
let controller = ["FirstViewController","SecondViewController","ThirdViewController"]
let pageContexts:[AnyObject]? = ["adf","asd","asd"]
presentControllerWithNames(controller, contexts: pageContexts)
If you call reloadRootControllersWithNames(NSArray, contexts: NSArray) onto the view controller, it will do as the function is titled: reload. Therefore, you have a view controller that refreshes all 3 of the items in the first Array you give, and then, since your current view controller calls willActivate() upon loading, it infinitely refreshes.
I don't have enough reputation to make this a comment, but my suggestion here is to find a method that you can call on an instance of the watch interface you want to in order to pass data.
What I mean is, if you have each interface as its own class, then you can make a method in the interface you want to get to that sets a property to whatever data you want to transfer before you present the interface.
I also use Objective-C more than Swift, but here's what my guess is as to what the Obj-C code would come to:
SecondWatchInterface *secondWatchInterface = [SecondWatchInterface new];
[SecondWatchInterface setSomeDataWithAStringValue:#"Foo"];
[self presentWatchInterface:SecondWatchInterface]
In Swift, I'm thinking this would equate to:
SecondWatchInterface *secondWatchInterface = SecondWatchInterface.new()
secondWatchInterface.setSomeDataWithAStringFile:"Foo"
presentWatchInterface(secondWatchInterface)
I'm unfamiliar with WatchKit myself; I typically use SpriteKit. I hope I helped identify what the problem was, at least!
To pass data between interface controllers you need to go for this method:
presentControllerWithName(“Second Watch Controller”, context: [“segue”:“pagebased”,“data”: "Data Passed Successfully”]);
Also, you can refer to this example: http://www.informit.com/articles/article.aspx?p=2272657&seqNum=3
Related
For our iOS programming class we must make a framework for Swift iOS. We had the idea of a framework simplifying CoreData manipulation. I began by creating a class where you put the NSManagedObjectContext created in AppDelegate at the beginning, so you don't have to write this long (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext anymore.
open class SimpleCoreData {
var context: NSManagedObjectContext
init(context: NSManagedObjectContext) {
self.context = context
}
func delete(entity: NSManagedObject) /*-> Bool*/ {
// some code
}
func getAll(entityClass: NSManagedObject.Type) throws -> [NSManagedObject]? {
// some code
}
func create(entityDescr: NSManagedObject.Type) -> NSManagedObject? {
// some code
}
But I would like it to be accessible from everywhere in the application, and this simplification would be useless if you have to instantiate this each time.
I was first thinking about a singleton, but I recently learned it wasn't a good practice.
So do you know any solution to make this accessible from everywhere in the client app? Or maybe singleton is okay in this case?
Keeping Rob Napier's excellent comments in mind, if you decide to avoid a singleton in this case, a common approach would be
Create an instance of your SimpleCoreData class in the app delegate when the app launches.
Have the app delegate pass this to your initial view controller. That view controller would have a SimpleCoreData property but would not create the instance-- it would expect one to be assigned by whichever code creates it, which here is the app delegate.
Repeat this pattern everywhere you need a SimpleCoreData. That is, when you create an object that needs a SimpleCoreData, make sure it has a property with that type, and assign a value when you create it. For view controllers, a good place to do this is in prepare(for:sender:), if you're using segues.
It's not necessary to create the SimpleCoreData in the app delegate, though. You could create it at the first point in the app hierarchy where it's needed, and pass it along from there. So if it's only needed in the second view controller in the hierarchy and in other objects loaded from there, create it in that view controller.
This doesn't make your SimpleCoreData instance available everywhere automatically, it means that you're creating one and then passing it around. Often that works fine, but as Rob notes it's not always the best approach. It can lead to passing an object along to an object that doesn't need it, because some other object that gets created later on does. For example if you need SimpleCoreData in your initial view controller but then not again until five levels down the hierarchy, you still need to pass it along every step of the way. That's an example of when a shared instance can be useful. It's not a singleton since other instances are allowed, but it's a default instance that can be used as needed.
I finally learned thanks to you that singletons aren't so evil, they can be used in some case, including this one, and it seemed in my case that it was a good choice. Maybe I will change it for a shared instance pattern.
So the singleton works well. Thank you everybody for your advices, I learned a lot in design patterns.
I have three Xibs (A, B, C). From A I am going to B. So If I have to pass data to A and get back to A, I have written a delegate and I am dismissing the Controller. This is fine.
But now my requirements are that I have to go from A to B and from B to C. Now from C I have to pass data to A and come back to A.
How to do this?
Note: I am not using StoryBoard or Navigation Controller. And Controller A is not root View Controller
Add a notification observer with a name in controller A, Then from where you want to send data (in your case B, C), From there post a notification with the name you are observing in controller A.
You can use NSNotificationCenter for passing data from viewcontroller to another view controllers.
You can try NSNotificationCenter as shown below,
Example:
In your ViewControllerA.m
-(void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(dataReceived:) name:#"passData" object:nil];
}
-(void)dataReceived:(NSNotification *)noti
{
NSLog(#"dataReceived :%#", noti.object);
}
In your ViewControllerC.m
-(void)gotoHome
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"passData" object:[NSDictionary dictionaryWithObject:#"Sample Data" forKey:#"dataDic"]];
[self.navigationController popToRootViewControllerAnimated:YES];
}
Check this example in below link:
https://stackoverflow.com/a/22501709/5349267
I extend the answer of Sommm as it is my wish to underline how important
MVC, the model-view-controller pattern,
as a design pattern in iOS as well as macOS applications really is and how useful it is if one obeys to it.
Good solution: Use NSNotificationCenter in order to let parts of your application communicate that don't know about each other usually. You register controllers that are waiting for information as observers for a specific message type and then post from other parts of your code what should be sent to the observers (using the specific message type the observers are waiting for).
Much better solution: Don't use NSNotificationCenter and instead design your application better and obey to the MVC design pattern.
The OP's initial question somehow shows (at least to my mind) a common misunderstanding: Don't try to create a specific UI flow and write your code accordingly but think of your application in a more general way first. As you don't give enough information on the question what you really want to do, I will assume you are generating an instance of a class User in your three XIBs called A, B and C.
Model: Write a class User that has the needed properties like firstname, surname and email
Controller: Write a controller UserController that holds an array of every instance of the class User that exists in your application.
View: Now (and only now!) think about your View. First question: Do you really need three XIBs or could you use one with three UIViews? The views could be IBOutlets of a class say UserViewController. Make this class the delegate of your single XIB file and connect the IBOutlets. Your UserViewController could then have a property user of the instance of User it represents and set the properties of user according to what has been inserted in the UITextFields for example.
If this is too complicated to you, you can use the NSNotificationCenter in order to send messages (with content if needed) between different parts of your application. If you find yourself using it very often: increased usage of this technique usually is a sign of a badly constructed application that needs some refactoring.
I have two view controllers that I am working on which both inherits from a Base view controller
class A_ViewController: BaseViewController
class B_ViewController: BaseViewController
Both of those VC interacts heavily with my firebase database. So I want a variable to keep track of all the downloaded items so those two VC can access it without the need to re-download the file again.
I tried to put a variable name in BaseViewController for the two A,B class to access
var allPostsDownloaded: [Post]!
So before A_VC downloads any data, it checks for this allPostsDownloaded variable and loads from it if the data exists. If it doesnt exist, I append to this variable. So when switching to B_VC, the same can be done and no data is re-downloaded when not required.
Reason I am not using segue or protocal to pass data around is that the two VC interacts quite heavly with my database. So it was alot cleaner to try and have a mutural data varaible to keep track of where things are.
However, the problem is that i
var allPostsDownloaded: [Post]!
gets called whenever I switch between A and B VC (Which are tabs). This will cause the variable to be empty and de-initialised.
I guess I could use a global variable instead but that is not good practice? Could anyone please explain why it gets re-called when new tab shows up? And the best solution for this.
as #avi mentioned create new singleton class, then you can pass and read easily. Below is an example
class PersistentData
{
static let sharedInstance = PersistentData()
// your global persistent variable
var allPostsDownloaded = [Post]()
}
So in your controllers you can simple read and set as below
// read
print(PersistentData.sharedInstance.allPostsDownloaded)
// set new data. this just example, hence depends on your case
PersistentData.sharedInstance.allPostsDownloaded.append(newPost)
PersistentData.sharedInstance.allPostsDownloaded = posts
also keep in mind that if you want to read new value when switching between tabs, you can get the updated in viewDidAppear or viewWillAppear
You can create a Singleton class with a instance variable and can save all downloaded data, and can access singleton class variable from any where of your project's classes.
I'm new to Xcode.I'm trying to figure out how to use showViewController.My question is how to call the UIViewController that to display ? via name or a identifier? And where can I find them ? In addition, the document says The default implementation of this method calls the targetViewControllerForAction:sender: method to locate an object in the view controller hierarchy that overrides this method,what does it mean? Should I call targetViewControllerForAction:sender:fist when using showViewController?
showViewController behavior basically depends on context you're app is in.
But calling it is really simple. All you need is reference to your UIViewController object(or it's subclass).
You can do it in couple of different ways:
If you're using Storyboards, give your storyboard view controller identifier, and use API call: UIStoryboard(name, bundle).instantiateViewControllerWithIdentifier(identifier). This gives you UIViewController that you should pass as an argument to showViewController. You could find information about API here: https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIStoryboard_Class/index.html#//apple_ref/doc/uid/TP40010909-CH1-SW6
Also, you could get your UIVIewController instance directly constructing it using proper initializer.
So: not worry about this targetViewController method, just get your object (initialize it via constructor or get it from storyboard), and pass it to show method.
In case you have further questions - feel free to ask.
So in my app I have the following situation:
BackendCommunicatingClass -> (owned by) -> ModelClass -> (owned by) -> HomescreenViewController
HomescreenViewController is a delegate for ModelClass.
ModelClass is a delegate for BackendCommunicatingClass.
Also on when the app launches for the first time, I have this:
WelcomeViewController -> (owned by) -> HomescreenViewController
HomescreenViewController is delegate for WelcomeViewController.
When the user types a username and password in the WelcomeViewController, this information needs to get all the way to BackendCommunicatingClass, and then all the way back to WelcomeViewController to display error if needed. Right now I have implemented this by passing information to each class in the communication chain, until it gets to BackendCommunicatingClass. The result is a lot of duplication of protocol methods and I feel like I'm doing it wrong.
What do you think?
Well I understand it is not the clearest solution, but without seing the code, and the purpose of your program, this what I suggest.
Implement Key Value Observing (KVO) in Back End view controller, observing change in the Home View Controller. As soon as Back end controller detect change in the text field, trough a dedicated variable in Home View controller, it fires all the operation it has to do.
When back end finish, it sends a NSNotification with the result of the operation. Home view controller which you have made listening to such custom notification, react to that and display error message or other staff.
It may sounds complicated, but KVO and notification are easy to implement, and there are plenty of docs and tutorial on the net.
If there is a clear 1:1 mapping of what those delegate protocols provide AND the delegate does not deal in UI stuff that nothing except the directly owning view controller should be concerned with, you could pass the delegate along to the end of the chain and set it directly as a delegate. This is what delegates are for - being able to allow an otherwise unconcerned object to communicate with another object.
That said, depending on how strict your layering policy is, you may prefer to encapsulate the information at every step by having different delegates.