UIActivityView Swift not functioning correcting? - ios

#IBAction func getData(sender: AnyObject) {
activitySpinner.startAnimating();
activitySpinner.hidden = false;
edisonArray[0].EdisonLocation = edison1Location.text!;
edisonArray[1].EdisonLocation = edison2Location.text!;
edisonArray[2].EdisonLocation = edison3Location.text!;
edisonArray[3].EdisonLocation = edison4Location.text!;
edisonArray[4].EdisonLocation = edison5Location.text!;
edisonArray[0].EdisonComment = edison1Comment.text!;
edisonArray[1].EdisonComment = edison2Comment.text!;
edisonArray[2].EdisonComment = edison3Comment.text!;
edisonArray[3].EdisonComment = edison4Comment.text!;
edisonArray[4].EdisonComment = edison5Comment.text!;
for(var i = 0; i < edisonArray.count ; i++){
var edison = edisonArray[i];
edison = startDataCollection(edison);
edisonArray[i] = edison;
}
edison1Data.text = "True"
edison2Data.text = "True"
edison3Data.text = "True"
edison4Data.text = "True"
edison5Data.text = "True"
if(!edisonArray[0].EdisonBool) { edison1Data.text = "False" }
if(!edisonArray[1].EdisonBool) { edison1Data.text = "False" }
if(!edisonArray[2].EdisonBool) { edison1Data.text = "False" }
if(!edisonArray[3].EdisonBool) { edison1Data.text = "False" }
if(!edisonArray[4].EdisonBool) { edison1Data.text = "False" }
activitySpinner.stopAnimating();
activitySpinner.hidden = true;
}
The code above is for a project I'm working on. I'm trying to get the activity spinner working every time I run this code the spinner is not animating. Can someone please help me with this.
activitySpinner is an object of UIActivityIndicatorView

You are running your work in the main thread. Which will stop the animation from working correctly. Additionally, you are calling start and stop animation on the same frame of the runloop. Which can also cause it to not animate.
Finally, you can not update the user interface of the background thread. So if you are working with UIKit controls you will need to do so on the main thread.
Matt points out the correct method of invoking again on the main thread. But I suspect the full workflow would look like this
activitySpinner.startAnimating();
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);())
{
//do any slow operations here in the background queue
doProcess();
//move back to the ui thread
dispatch_async(dispatch_get_main_queue())
{
//update any user interface info based on the above processing
updateUi();
activitySpinner.stopAnimating();
}
}

Like this:
#IBAction func getData(sender: AnyObject) {
activitySpinner.startAnimating();
dispatch_async(dispatch_get_main_queue()) { // <--
activitySpinner.hidden = false;
edisonArray[0].EdisonLocation = edison1Location.text!;
// ...
activitySpinner.stopAnimating();
activitySpinner.hidden = true;
}
}
But note that this will not make your code correct. If startDataCollection is time-consuming, you should not be doing it on the main thread. However, that's another question.

Related

iOS swift while loop freeze my app

I'm developing an app where a user choose his accommodation and pick a time from date picker so the user can know what time the buss will arrive to his accommodation , on the simulator and iPad I'm having the appropriate results however I'm facing this issue on iPhone real device, this is the code :
mTimeString = "5:07 AM"
it will be searched in the array if not found , minus seconds until it matches results in the array . but while loop is freezing my app , i tried to surround it by :
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT ,0)
dispatch_async(queue){}
its not freezing anymore but the I'm not getting the results according to the array
if(defaults.stringForKey(accommodationChoiceKey)?.toInt() == 40) {
var array = ["12:05 AM","12:25 AM","12:45 AM","1:05 AM","1:25 AM","1:45 AM","2:05 AM","2:25 AM","2:45 AM","3:05 AM","3:25 AM","3:45 AM","4:05 AM","4:25 AM","4:45 AM","5:05 AM","5:25 AM","5:45 AM","6:05 AM","6:25 AM","6:45 AM","7:05 AM","7:25 AM","7:45 AM","8:05 AM","8:25 AM","8:45 AM","9:05 AM","9:25 AM","9:45 AM","10:05 AM","10:25 AM","10:45 AM","11:05 AM","11:25 AM","11:45 AM","12:05 PM","12:25 PM","12:45 PM","1:05 PM","1:25 PM","1:45 PM","2:05 PM","2:25 PM","2:45 PM","3:05 PM","3:25 PM","3:45 PM","4:05 PM","4:25 PM","4:45 PM","5:05 PM","5:25 PM","5:45 PM","6:05 PM","6:25 PM","6:45 PM","7:05 PM","7:25 PM","7:45 PM","8:05 PM","8:25 PM","8:45 PM","9:05 PM","9:25 PM","9:45 PM","10:05 PM","10:25 PM","10:45 PM","11:05 PM","11:25 PM","11:45 PM"]
while (find(array, mTimeString) == nil) {
choiceToSeconds--
var newmTime = x.dateByAddingTimeInterval(Double(choiceToSeconds))
var mTimeString = dateFormatter.stringFromDate(newmTime)
if (find(array, mTimeString) != nil) {
transportationLabel.text = mTimeString
break
}
getReady(newmTime)
}
}
You are calculating on Background thread which is okay , but you should NEVER update UI element from background thread ( transportationLabel.text = mTimeString ) , this should be done from main Thread , for example
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
if(defaults.stringForKey(accommodationChoiceKey)?.toInt() == 40) {
var array = ["12:05 AM","12:25 AM","12:45 AM","1:05 AM","1:25 AM","1:45 AM","2:05 AM","2:25 AM","2:45 AM","3:05 AM","3:25 AM","3:45 AM","4:05 AM","4:25 AM","4:45 AM","5:05 AM","5:25 AM","5:45 AM","6:05 AM","6:25 AM","6:45 AM","7:05 AM","7:25 AM","7:45 AM","8:05 AM","8:25 AM","8:45 AM","9:05 AM","9:25 AM","9:45 AM","10:05 AM","10:25 AM","10:45 AM","11:05 AM","11:25 AM","11:45 AM","12:05 PM","12:25 PM","12:45 PM","1:05 PM","1:25 PM","1:45 PM","2:05 PM","2:25 PM","2:45 PM","3:05 PM","3:25 PM","3:45 PM","4:05 PM","4:25 PM","4:45 PM","5:05 PM","5:25 PM","5:45 PM","6:05 PM","6:25 PM","6:45 PM","7:05 PM","7:25 PM","7:45 PM","8:05 PM","8:25 PM","8:45 PM","9:05 PM","9:25 PM","9:45 PM","10:05 PM","10:25 PM","10:45 PM","11:05 PM","11:25 PM","11:45 PM"]
while (find(array, mTimeString) == nil) {
choiceToSeconds--
var newmTime = x.dateByAddingTimeInterval(Double(choiceToSeconds))
var mTimeString = dateFormatter.stringFromDate(newmTime)
if (find(array, mTimeString) != nil) {
// This should be done on Main Thread
dispatch_async(dispatch_get_main_queue()) {
transportationLabel.text = mTimeString
}
break
}
getReady(newmTime)
}
}
}
Try replacing
transportationLabel.text = mTimeString
by
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
transportationLabel.text = mTimeString
}];
UI operations must be executed from main thread
EDIT:
In Swift:
NSOperationQueue.mainQueue().addOperationWithBlock({
transportationLabel.text = mTimeString
})

Display image when bool variable is true

How can i do this:
I have 5 incentive images. I need to display each image if my bool variable is true.
Here's What I did:
BOOL var1 = true;
BOOL var2 = true;
BOOL var3 = false;
BOOL var4 = true;
BOOL var5 = false;
if(var1)
{
cell.incentive1.hidden = false;
}
if(var2)
{
cell.incentive2.hidden = false;
}
if(var3)
{
cell.incentive3.hidden = false;
}
if(var4)
{
cell.incentive4.hidden = false;
}
if(var5)
{
cell.incentive5.hidden = false;
}
this is working..
I have a follow up question,
how will i be able to display the var4's uiimageview var2's uiimageview. I need the uiimageview to be dynamically created. That when the app detects the bool variables that are true there will be no gaps.
thanks..
When you use if..else if condition, if any one condition passes then the remaining will not be evaluated.
So for fixing the issue, you need to change all to if conditions.
But I'll suggest using like following is a better approach (There is no need of if else conditions):
cell.incentive1.hidden = !var1;
cell.incentive2.hidden = !var2;
cell.incentive3.hidden = !var3;
cell.incentive4.hidden = !var4;
cell.incentive5.hidden = !var5;
You should not use if...else as all images are independent. You should:
if(var1)
{
cell.incentive1.hidden = false;
}
if(var2)
{
cell.incentive2.hidden = false;
}
if(var3)
{
cell.incentive3.hidden = false;
}
if(var4)
{
cell.incentive4.hidden = false;
}
if(var5)
{
cell.incentive5.hidden = false;
}
You've got chained if..else if statements going on there. This means that once one of the conditions is satisfied, the entire evaluation is done and it jumps to the next bit of code. Remove the else everywhere, so that every condition is evaluated in isolation.
Try this.
cell.incentive1.hidden = (var1 == true)?true:false;
cell.incentive2.hidden = (var2 == true)?true:false;
cell.incentive3.hidden = (var3 == true)?true:false;
cell.incentive4.hidden = (var4 == true)?true:false;
cell.incentive5.hidden = (var5 == true)?true:false;
As given code if var 1 is true then it will goes to 1st block other wise it goes to next.
and best way to hide and display images you can set alpha 0 for hide and 1 for display.

XNA Controls Settings

I have a huge problem with editing controls for my game.. I have an ingame button and when you click it. The "Choose your key.." text appears, but I don't know how to actually set it up..
I have made a "waiting for input" bool.. THIS IS NOT THE REAL CODE IT'S HOW I IMAGINE IT TO BE
if (buttonIsClicked) waitinForInput = true;
while(waitingForInput)
{
kbState = Keyboard.GetState();
somehow convert it to Keys.(STH);
if (Keys.STH != defaultKeys)
{
defaultKeys = Keys.STH;
waitingForInput = false;
}
}
Is there a way to do this.. Simpliest as I can? And sorry for my bad english.. Made this in a hurry and not my native language..
Thanks for any help.. :-)
Something like this:
KeyboardState currentKeyboardState = new KeyBoardState();
KeyboardState previousKeyboardState = new KeyBoardState();
Keys jumpKey = Keys.Space;
public void handleInput()
{
lastKeyboardState = currentKeyboardState;
currentKeyboardState = Keyboard.GetState(PlayerIndex.One);
bool waitingForKey = false;
if(currentKeyboardState.IsKeyDown(Keys.A) && waitingForKey == false)
{
waitingForKey = true;
}
if(waitingForKey == true)
{
//currentKeyboardState.GetPressedKeys() returns a list of pressed keys,
//So, currentKeyboardState.GetPressedKeys()[0] returns the first pressed key
if(currentKeyboardState.GetPressedKeys().Count() > 0)
{
jumpKey = currentKeyboardState.GetPressedKeys()[0];
waitingForKey = false;
}
}
}

iOS UIAutomation UIAElement.isVisible() throwing stale response?

I'm trying to use isVisible() within a loop to create a waitForElement type of a function for my iOS UIAutomation. When I try to use the following code, it fails while waiting for an element when a new screen pops up. The element is clearly there because if I do a delay(2) before tapping the element it works perfectly fine. How is everyone else accomplishing this, because I am at a loss...
Here's the waitForElement code that I am using:
function waitForElement(element, timeout, step) {
if (step == null) {
step = 0.5;
}
if (timeout == null) {
timeout = 10;
}
var stop = timeout/step;
for (var i = 0; i < stop; i++) {
if (element.isVisible()) {
return;
}
target.delay(step);
}
element.logElement();
throw("Not visible");
}
Here is a simple wait_for_element method that could be used:
this.wait_for_element = function(element, preDelay) {
if (!preDelay) {
target.delay(0);
}
else {
target.delay(preDelay);
}
var found = false;
var counter = 0;
while ((!found) && (counter < 60)) {
if (!element.isValid()) {
target.delay(0.5);
counter++;
}
else {
found = true;
target.delay(1);
}
}
}
I tend to stay away from my wait_for_element and look for any activityIndicator objects on screen. I use this method to actual wait for the page to load.
this.wait_for_page_load = function(preDelay) {
if (!preDelay) {
target.delay(0);
}
else {
target.delay(preDelay);
}
var done = false;
var counter = 0;
while ((!done) && (counter < 60)) {
var progressIndicator = UIATarget.localTarget().frontMostApp().windows()[0].activityIndicators()[0];
if (progressIndicator != "[object UIAElementNil]") {
target.delay(0.25);
counter++;
}
else {
done = true;
}
}
target.delay(0.25);
}
Here is a simple and better one using recursion. "return true" is not needed but incase u want it.
waitForElementToDismiss:function(elementToWait,waitTime){ //Using recursion to wait for an element. pass in 0 for waitTime
if(elementToWait && elementToWait.isValid() && elementToWait.isVisible() && (waitTime < 30)){
this.log("Waiting for element to invisible");
target.delay(1);
this.waitForElementToDismiss(elementToWait, waitTime++);
}
if(waitTime >=30){
fail("Possible login failed or too long to login. Took more than "+waitTime +" seconds")
}
return true;
}
Solution
I know this is an old question but here is my solution for a situation where I have to perform a repetitive task against a variable timed event. Since UIAutomation runs on javascript I use a recursive function with an empty while loop that checks the critical control state required before proceeding to the next screen. This way one never has to hard code a delay.
// Local target is the running simulator
var target = UIATarget.localTarget();
// Get the frontmost app running in the target
var app = target.frontMostApp();
// Grab the main window of the application
var window = app.mainWindow();
//Get the array of images on the screen
var allImages = window.images();
var helpButton = window.buttons()[0];
var nextButton = window.buttons()[2];
doSomething();
function doSomething ()
{
//only need to tap button for half the items in array
for (var i=0; i<(allImages.length/2); i++){
helpButton.tap();
}
//loop while my control is NOT enabled
while (!nextButton.isEnabled())
{
//wait
}
//proceed to next screen
nextButton.tap();
//go again
doSomething();
}

Flash: How to preload upcoming SWF while current one plays

I have a Flash slideshow that plays SWFs listed in an XML file. I would like to have the upcoming SWF load while the current one displays. I've tried all sorts of combinations of LoadMovie and LoadMovieNum, including creating an empty movie clip, but there's something I'm just not getting.
Right now, after making the first round through all the files, it transitions smoothly from slide to slide, but I'd like for it to preload so that it transitions without the "Loading..." screen the first time around.
It can be viewed here: slideshow
Where should I put the LoadMovie line to load the next file (image[p+1]), and how should it look?
function loadXML(loaded) {
if (loaded) {
xmlNode = this.firstChild;
image = [];
description = [];
total = xmlNode.childNodes.length;
for (i=0; i<total; i++) {
image[i] = xmlNode.childNodes[i].childNodes[0].firstChild.nodeValue;
description[i] = xmlNode.childNodes[i].childNodes[1].firstChild.nodeValue;
}
firstImage();
} else {
content = "file not loaded!";
}
}
xmlData = new XML();
xmlData.ignoreWhite = true;
xmlData.onLoad = loadXML;
xmlData.load("xmlfile.xml");
/////////////////////////////////////
back_btn.onRelease = function ()
{
backImage();
};
next_btn.onRelease = function ()
{
nextImage();
};
p = 0;
function nextImage() {
if (p<(total-1)) {
p++;
trace(this);
_root.mc_loadfile.loadMovie (image[p]);
_root.movie_name.text = image[p];
next_btn._visible = true;
back_btn._visible = true;
if (getBytesLoaded() == getBytesTotal())
slideshow();
}
else if (p == (total-1)) {
p = 0;
firstImage();
}
}
function backImage() {
clearInterval(myInterval);
if (p>0) {
--p;
_root.mc_loadfile.loadMovie (image[p]);
_root.movie_name.text = image[p];
next_btn._visible = true;
if (p != 0) {
back_btn._visible = true;
}
else {
back_btn._visible = false;
}
slideshow();
}
}
I'd appreciate any help.
You can do it with the MovieClipLoader class. A brief tutorial can be found at actionscript.org, or you can check the docs on it.

Resources