My application has deep navigational chains of 8+ screens deep (Wizard-style). When i'm editing a View Controller, and i want to make a quick visual change and re-test, As a tester, I have to go through the full flow to end up where I was before recompiling, in the same Data state. Is there a way that Xcode can somehow preserve the application state, and re-run the same view controller?
If there was an automated way to detect the last launched screen, and re-display it after the recompile, that would save a lot of developers a lot of time.
I realize something like this can be built custom. Something like:
IF A Certain Debug Flag is ON:
- Retrieve from NSUserDefaults the Class Name of the last controller used, and redisplay it.
The problem with this is: Data State and Navigation State will not be preserved. Also, all other object state which invokes and depends on your controller will not be included. That's why I need a more universal solution.
IF A Certain Debug Flag is ON: - Retrieve from NSUserDefaults the Class Name of the last controller used, and redisplay it.
The problem with this is: Data State and Navigation State will not be preserved.
But this is exactly the problem that the built-in state saving and restoration mechanism is intended to solve, is it not?
https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/PreservingandRestoringState.html
I recommend you use a User Interface target and then create an XCTestCase that works on your view controller and exercise it. Use the new record button in Xcode 7 to get you started with the test case. Familiarize yourself with some of the new queries it uses for some of the dynamic information you may be creating.
Another option would be to inject your test case's UI state into the application delegate in the setup function of an XCTestCase. Then it will need custom logic to navigate to the correct view controller. Then your test case could focus on just that ViewController once the Application delegate has navigated to it.
Of course you can use the debugger and breakpoints in the Test Case and your View Controller while UI Testing. By "scripting" this you do significantly less manual clicking on a device to test a ViewCOntroller
Also you've now got a Test! Hopefully worth something to you down the road when you change something
Related
My team and I have to make a license plate scanning app as a school project. With that, we have comments and pictures which can be added to cargo. Whenever the user scans a plate they also get the chance to change the checked info in case of a mistake. The problem is that whenever we delete data from the scanned plate it doesn't show on the screen that it has been deleted until we go to another screen. The same goes for the lazy column which we use for inserting new instances of comments and pictures. The data doesn't show on screen until we turn our screen or go back to another screen. private val pictureList = mutableListOf() is what we use for the pictures and for the text we use var countryCode by remember { mutableStateOf(CountryCodeText) }
var licenseNumber by remember { mutableStateOf(LicenseNumberText) }. pictureList is a global variable and the other ones are local variables which use global variables in the mutableStateOf. How can we make sure that the UI updates whenever the data changes? In advance I want to say thanks for the help! (Code is written in Kotlin and jetpack compose)
Just replace the mutableListOf() with a mutableStateListOf(...), and prefer to keep all the state logic confined to a ViewModel. The viewmodel should preferably be only one for the entire app, and the entire app should have only one activity.
The viewmodel should act as a single source of truth for the entire activity's UI state, while also handling all the updates to the UI efficiently.
The #Composables should only be incharge of displaying the state, and sending events to the viewmodel to update the state, for example, an onClick event may be sent up to the viewmodel by a button too trigger a state change in another part of the app.
Take this codelab to learn all about state in Compose (Well, not all, really, but good starter).
Also, changing screens destroys all the #Composables of the current screen, and so when you ce back there, all the #Composables are re-created, and the correct data is fetched. If you wish to trigger "recompositions" upon changing a variable, you must ensure that the concerned variable is a state-holder, i.e., initialized with one of the pre-built state initializers, like mutableStateOf(), or mutableStateMapOf, etc.
We usually have a mutableState*Of format for determining whether a pre-built state initializer is available. The most common ones are covered, obviously, but if not, you'll need to create a new type of initializer yourself, and if that is not something you know how to do, currently, you can just go about checking whether the type of data you wish to store is Immutable. If so, you can just wrap it in a mutableStateOf<DataType>() call, and it will trigger the recompositions. Know that this is not as efficient as pre-built initializers, but definitely gets the job done.
Also, I suggest you take the compose-pathway to get the basics down. It covers everything ranging from creating a simple UI using basic pre-built Layouts to creating a complex animation-driven application using custom Layouts.
So, definitely a lot to take it, but I hope you get there.
Happy composing,
I am playing around with the new UI testing introduced in Xcode 7 beta. In one of my UI testing scenarios, I need to add some code that does the same thing as clicking Simulator -> Reset Content and Settings in the setup() of my test file, which is a XCTestCase. Can the reset be done programmatically? Or, can we mimic the effect of a factory reset on an app in test code?
Not entirely programmatically, but you can always write a bash file to delete:
${user.home}/Library/Application Support/iPhone Simulator/${simulator.version}
That will clear the settings on the simulator.
My understanding is that you won't be able to that from within your app, as apps are sandboxed.
Usually people were using shell scripts or apple scripts. However, using hard reset is absolutely not necessary.
You shouldn't care about data in other apps, you should care only about the data in your app. You can always delete your app data (files, user defaults) in the beginning of your tests. So, why should you do a hard reset?
A better solution is mocking. If your test supposes that, for example, some variable in NSUserDefaults is not set, you don't have to care about the actual value stored there, just mock the method your implementation is using (e.g. objectForKey: and let it return nil.
So i have a titanium app, and i just read about single contexts. (Incidentally, somebody here should write a book about programming in titanium... the only one out there doesn't really mention single contexts or any of that new-fangled stuff. Heck, make it an eBook. I'd buy it)
The titanium documentation stresses their use (http://docs.appcelerator.com/titanium/latest/#!/guide/Coding_Strategies-section-29004891_CodingStrategies-Executioncontexts) and then politely forgets how to implement a single context!!
So, question:
Let's say i have the awesomeWidget page - this just shows a button, and when you click on a button a new screen appears.
The aswesomeWidget page is accessed through another page - it is not from the root of the titanium app.
Keeping to single contexts, how do i add the view that the button creates to the current window?
Do I:
keep a global pointer to the current (and only) window?
pass the variable holding the current window down to all the following pages that use it
something else?
First off, Titanium keeps a reference to your current window anyway for you, so this use case is easy. For example:
awesomeWidgetButton.addEventListener('click' function(e) {
var yourView = Ti.UI.createView({...});
Titanium.UI.currentWindow.add(yourView);
});
If you want to dig further, the concept of a single context is closely tied to the use of CommonJS modules and the require keyword. It is very simple to keep a single context, just never open a window with the url component filled out, and liberally use the require() keyword. Other than that, its up to your imagination to keep track of who points to what and vice versa, there are standard patterns and best practices that apply here (MVC, Singletons, just keep it simple) just as in coding in any other language.
I have some NSManagedObject subclass in my app, and I'm trying to understand when and how to save changes.
I will try to explain myself, for example class A is NSManagedObject subclass.
During app life cycle I do:
App launched
...
Create an instance of class A
...
Change some properties of A instance
...
App go to background
...
App becomes active again
...
Change some more properties of A instance
...
App terminates
When do I need to call [context save:] ??
Do I call it after every change in A instance? Or maybe I call it only when app go to background?
Should I call it after creation or deletion of any A instance?
A nice approach is place UIManagedDocument in your AppDelegate. Then you can call [context save] whenever some change occurs in the app (like a crash). The order I like to follow is something like:
Create UIManagedDocument object (in application did load or wherever)
and assign it to a property
Setup the document (check whether it exist on disk or is already open, etc.. and respond accordingly)
Pass the UIManagedObjectContext to the initial UIViewController in your app (from there you can pass the context to other view controllers)
UIManaged document will save the context for you.
Take a look at the UIManagedDocument documentation to configure persistent store options (you send an NSDictionary of options to your UIManagedDocument instance, see the first example through the link below).
UIManagedDocument documentation:
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIManagedDocument_Class/Reference/Reference.html
Also see the CoreData lecture and demo (lectures 13 and 14) of the iPhone and iPad application development course with Paul Hegarty available free on iTunesU (Fall 2011).
The data will not be saved to the persistent store until you call save. So, it depends on what you want in your app. If you want it to be able to recover the last value it ever had, then you should save after each modification.
Easy change is to just save after making modifications.
You could do something a bit more fancy, like only save after some set amount of time, so many changes are grouped together... and catch any event that will put your app in the background and then save...
But, that's what UIManagedDocument does automatically for you, so you could just use that instead.
Depending on the amount of changes that you make and the volume of data that needs to be saved with each change, yo can choose to save a little or a lot. If you are just saving a string or a number or a bool, then go ahead and call save: on your context as soon as the changes were made.
If it is a lot of data, you may want to coalasce your changes and then save it on a background queue so that you are not blocking the main queue. This way you are not waiting to go to the background to perform your saves.
Tim
I have a Eclipse plugin that uses a view which extends ViewPart. ViewPart has a saveState method which requires an IMemento.
I added my code to saveState and the corresponding init method and it works. Unfortunately, saveState is only called if the entire workspace is shutting down. My view is not of such great importance that I can expect it to be opened the entire time. Hence, it would be cool if saveState would be called on view closure.
I found a view-part listener as mean to react on view closure, but what I do not get is where the IMemento comes from. Where do I get the memento object that is used on workspace closure? Or where do I have to store my own memento object to make the view part use it in the init method if the view is (re)opened?
#Override
public void saveState(IMemento memento) {
super.saveState(memento);
memento = memento.createChild(MEMENTO_GUI_STATE);
memento.putBoolean(MEMENTO_IS_FLAT, !isHierarchicalModeActive());
memento.putBoolean(MEMENTO_IS_CATEGORY_MODE_ACTIVE, comboViewer.isVisible());
}
This is my saveState - can I tell my view somehow tell to call it every time the view closes?
Take a look at this question in the Eclipse FAQ:
Storing view state is done in two commons ways, depending on whether
you want to store settings between workbench sessions or across
invocations of your view. The first of these facilities is found
directly on IViewPart. When the workbench is shut down, the method
saveState is called on all open views.
Another mechanism for persisting view state is the JFace
IDialogSettings facility. The advantage of dialog settings over the
view save/init mechanism is that you can control when settings are
persisted. The saveState method is called only if your view is open
when the workbench shuts down, so it is not useful for storing view
state when the view is closed by the user. Dialog settings, on the
other hand, can be changed and persisted whenever you want.
Go to this other question or to the Eclipse documentation itself for the settings mechanism.
Well this could be "a bit" ugly but nothing else came to my mind: store memento variable as a field variable, initialize it in your init(IViewSite site, IMemento memento) method, override dispose() and call saveState(IMemento memento) explicitely.
You can read and write your own XMLMemento from your org.eclipse.core.runtime.Plugin.getStateLocation() at any time you want. As #BelaViser mentioned, you could write your file in your IViewPart#dispose() method and read it in your view constructor.