I am begining to SWIFT. I have tried following code to check how function call is working. Function call is working fine, as our wish. But, in PARSE, the order is not working in the parse statement. Parse statement get executed atlas when all function gets over. How to solve this.
if I run this code, I am getting output like,
MY OUTPUT:
START
FIRST CLASS TOP
FIRST CLASS BOTTOM
SECOND CLASS
THIRD CLASS
END
WELCOME TO PARSE // WHY THIS LINE IS PRINTING LAST??
But, I need output like,
REQUIRED OUTPUT:
START
FIRST CLASS TOP
WELCOME TO PARSE //I NEED THIS LINE TO BE EXECUTE IN ORDER.
FIRST CLASS BOTTOM
SECOND CLASS
THIRD CLASS
END
MY CODING IS BELOW. Kindly check and guide me.
class ViewController: UIViewController {
let one_1 = class_1()
let second_2 = class_2()
let third_3 = class_3()
override func viewDidLoad() {
super.viewDidLoad()
println("START")
one_1.one()
second_2.second()
third_3.third()
println("END")
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
//CLASS_1
class class_1 {
var par_query = PFQuery(className: "story")
func one() {
println("FIRST CLASS TOP")
par_query.findObjectsInBackgroundWithBlock({(NSArray objects, NSError error) in
if (error != nil) {
NSLog("error " + error.localizedDescription)
}
else {
println("WELCOME TO PARSE")
}//ELSE ENDING
}) //PARSE ENDING
println("FIRST CLASS BOTTOM")
}
}
//CLASS_2
class class_2 {
func second() {
println("SECOND CLASS")
}
}
//CLASS_3
class class_3 {
func third() {
println("THIRD CLASS")
}
}
It has nothing to do with parse.com in particular, it behaves that way because findObjectsInBackgroundWithBlock is executed asynchronously.
You can read about that here.
UPDATED:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
//Do some time comsuming calculation
//And when it's done
dispatch_async(dispatch_get_main_queue()) {
//Update the UI with your results
}
}
UPDATED 2
Let me put it that way: if you print anything, like "WELCOME TO PARSE" in an asynch closure, you cannot determine when it will be executed. I will mark with an * that where can be the "WELCOME TO PARSE" message with your current code:
START
FIRST CLASS TOP
FIRST CLASS BOTTOM
*
SECOND CLASS
*
THIRD CLASS
*
END
*
If you want to print the exact lines as you want, you could do two things:
Do not put a println in the asynch block
Put "FIRST CLASS BOTTOM" in your asynch block, and put also
class_2().second()
class_3().third()
in the asych block, so that will be called after the block is executed. However, I do not recommend this, it's just for the example.
Related
I have a request to a server (I am using VK SDK). So I want to move all the stuff to a different place, then call it and get response back.
Here is what I have now:
object GetAlbumsService {
fun getAlbums():GetAlbumsResponse{
lateinit var responseObject: GetAlbumsResponse
val request = VKRequest("photos.getAlbums", VKParameters.from("need_system", "1"))
request.executeWithListener(object: VKRequest.VKRequestListener(){
override fun onComplete(response: VKResponse?) {
responseObject = Gson().fromJson(response?.json.toString(), GetAlbumsResponse::class.java)
}
})
return responseObject
}
}
But responseObject remains null. Am I right that onComplete function have no time to fill responseObject? If so, what can I do?
You can't return the result of an asynchronous callback from the function that initiates the background work. But you can allow the calling function to pass a callback.
fun getAlbums(onComplete: (GetAlbumsResponse) -> Unit) {
val request = VKRequest("photos.getAlbums", VKParameters.from("need_system", "1"))
request.executeWithListener(object: VKRequest.VKRequestListener(){
override fun onComplete(response: VKResponse?) {
responseObject = Gson().fromJson(response?.json.toString(), GetAlbumsResponse::class.java)
onComplete(responseObject)
}
})
}
Then from where you call this:
GetAlbumsService.getAlbums { response ->
// Do something with response
}
The code inisde the lambda is called when the result is ready.
You can also look into using coroutines, but that's too much to explain from scratch in an answer here.
Once in a while, I get errors like:
Warning: Attempt to present <Controller3> on <Controller1> which is already presenting <Controller2>
I understand that the next controller needs to be presented on the controller that's at the top of the stack (Controller2), not a controller somewhere below (Controller1).
Instead of fixing such errors one-off, how do we design our app to prevent this problem once and for all?
One clean solution to this problem is a navigation controller.
If you can't or don't want to use one, you can easily simulate it on a normal view controller:
extension UIViewController {
var topViewController: UIViewController {
return presentedViewController == nil ? self : presentedViewController!.topViewController
}
// If the topmost view controller is an instance of one of the given classes, it's popped.
// Then, the given view controller, if any, if pushed.
//
// This function can be called on any of the view controllers in the stack.
func pop(ifOneOf: [AnyClass], thenPush: UIViewController? = nil) {
if topViewController.presentingViewController != nil && topViewController.isKindOfOneOf(ifOneOf) {
topViewController.dismiss(animated: false, completion: {
self.pop(ifOneOf: [], thenPush: thenPush)
})
return
}
if thenPush != nil {
push(thenPush!)
}
}
// Pushes the given view controller onto the stack.
//
// This method can be called on any of the view controllers in the stack.
func push(_ child: UIViewController) {
topViewController.present(child, animated: true)
}
}
extension NSObjectProtocol {
func isKindOfOneOf(_ classes: [AnyClass]) -> Bool {
for clazz in classes {
if isKind(of: clazz) {
return true
}
}
return false
}
}
As you can see, this provides push() and pop(), similar to a navigation controller. Further, you can call these methods on any controller in the stack, and it will automatically redirect them to the topmost controller, preventing the error in the question.
This extension also fixes the problem that if you want to dismiss a controller and present another, you need to present only in the completion block, even if you're dismissing without an animation. Otherwise, you'll get the same error as above. This extension fixes all these problems.
In an effort to properly instantiate Typescript objects from data received over HTTP as JSON, I was exploring the possibility of using the for..in loop coupled with .hasOwnProperty() like so:
class User {
private name: string;
private age: number;
constructor(data: JSON) {
console.log('on constructor\ndata', data);
for (var key in data) {
console.log('key:', key);
if (User.hasOwnProperty(key)) {
console.log('User has key:', key);
this[key] = data[key];
}
}
}
displayInfo(): string{
return JSON.stringify(this);
}
}
let button = document.createElement('button');
button.textContent = "Test";
button.onclick = () => {
try{
let json = JSON.parse('{"name": "Zorro","age": "24"}');
let usr = new User(json);
console.log(usr.displayInfo());
}catch (error){
alert(error);
}
}
document.body.appendChild(button);
Using similar code in my project fails completely. That is expected as the compiled JS code has no awareness of the private TS vars and so, hasOwnProperty is always false.
However, I was using the Typescript Playground, and running that code there produces the following output in the console:
on constructor
data Object {name: "Zorro", age: "24"}
key: name
User has key: name
key: age
{"name":"Zorro"}
As you can see, there are clearly some unexpected things happening here. The first key is recognized and the new User instance is initialized with the value from the JSON, yet that does not happen for the second key.
Can someone explain why this happens?
As was pointed out in the comments, you should be using this.hasOwnProperty instead of User.hasOwnProperty. And as you noticed, this code is busted anyway because the property declarations in the class don't actually create own properties on the object (they would need to be initialized for this to happen).
But why did you get a hit on the name key? The User object is a constructor function for your class. Functions do have a name property:
function fn() { }
console.log(fn.name); // prints 'fn'
They don't have an age property, of course.
Your constructor would of course just have to look like this, if you want to construct User instances from plain JavaScript objects:
constructor(data: any) {
this.name = data.name;
this.age = data.age;
}
I'm building an exercise app. I have an array of exercises in my TableViewController, with each cell displaying a different exercise. The cells segue to a UIViewController. Within the UIViewController I would now like a user to be able to skip to the next exercise without having to go back to the TableViewController.
How can I refresh my ViewController containing the new data of the next exercise? (Similar to the reloadData method when constructing tables?)
I'm getting the next exercise in the array, but my page isn't refreshing.
My code:
var exercise: Exercise?
var exerciseList: [Exercise]!
// toolbar item button pressed:
#IBAction func nextExercise(sender: UIBarButtonItem) {
if let currentIndex = exerciseSet.indexOf(exercise!) {
let nextIndex = currentIndex + 1
let nextExercise = exerciseList[nextIndex]
reloadData(nextExercise)
}
}
private func reloadData(displayedExercise: Exercise){
exercise = displayedExercise
self.view.setNeedsDisplay()
}
Thanks!
You can use our codes and easily can do pagination. We already answered your question.
Example for load more indexs;
if indexPath.row == privateList.count - 1 { // last cell
if totalItems > privateList.count { // more items to fetch
loadItem() // increment `fromIndex` by 20 before server call
}
}
Swift tableView Pagination
Thanks
Api Call
http://localhost:8888/api/v1/users/100 //doesn't exist
Html Call
http://localhost:8888/admin/users/100 //doesn't exist
Obviously, I don't want the Html Call exception to return json data and I don't want the Api Call to return Html Data.
I am not exception handling in the controller. I am exception handling in my UserRepository. As such, my controllers are just returning a result from the user repository.
class Sentry2UserRepository implements UserInterface {
public function findById($id) {
try {
return Sentry::findUserById($id);
}
catch (\Cartalyst\Sentry\Users\UserNotFoundException $e) {
// Do something here
return false;
}
}
}
Question 1: What is the normal / proper way of passing an error back to controller so that it will know what to display?
Question 2: Is there a standard json API format for exceptions / errors?
Question 3: Is it good practice for a Web UI to consume an internal JsonApi? Or am I doing things the right way at the moment with my WebUi controllers Querying the same Repositories as the Api?
Try this magic in your filters.php:
App::error(function(Exception $exception, $httpCode)
{
if (Request::is('api/*')){
return Response::json( ['code' => $exception->getCode(), 'error' => $exception->getMessage()], $httpCode );
}else{
$layout = View::make('layouts.main');
$layout->content = View::make('errors.error')->with('code', $exception->getCode())->with('error', $exception->getMessage())->with('httpCode',$httpCode);
return Response::make($layout, $httpCode);
}
});
First of all, I think your approach in Sentry2UserRepository is not bad, it's ok, IMO.
Question 1: What is the normal / proper way of passing an error back
to controller so that it will know what to display?
Well, IMO, depending on the application you should determine how you should handle exceptions. You mentioned so that it will know what to display and in this case it depends on how and what information you need from an exception to take the next action after an exception occured. now if you need the error message then you may return the return $e->getMessage() so you'll exactly know what actually happened. There are many ways to do this, for example, using a single catch :
try{
// ...
}
catch( Exception $e )
{
if ($e instanceof UserNotFoundException) {
// it's an instance of UserNotFoundException, return accordingly
}
elseif ($e instanceof SomethinElseException) {
// it's an instance of SomethinElseException, return accordingly
}
}
Also, you can use different custom exception classes and may use multiple catch blocks, i.e.
class AnException extends Exception
{
public function customErrorMessage()
{
return `AnException occurred!`
}
}
class AnotherException extends Exception
{
public function customErrorMessage()
{
return `AnotherException occurred!`
}
}
Then catch using multiple catch blocks, i.e.
try
{
// ...
}
catch(AnException $e)
{
return $e->customErrorMessage();
}
catch(AnotherException $e)
{
return $e->customErrorMessage();
}
catch(Exception $e)
{
return $e->getMessage();
}
Question 2: Is there a standard json API format for exceptions / errors?
Question 3: Is it good practice for a Web UI to consume an internal JsonApi? Or am I doing things the right way at the moment with my WebUi controllers Querying the same Repositories as the Api?
Actually I don't know about such an api and you are doing right, IMO. It's because, you have this
class Sentry2UserRepository implements UserInterface {
public function findById($id) {
try {
return Sentry::findUserById($id);
}
catch (\Cartalyst\Sentry\Users\UserNotFoundException $e) {
// Do something here
return false;
}
}
}
So, it's possible to write code in controller something like this
if(findById(5)) {
// found and dump it to the view
}
else {
// show "Not Found !", false will be back only for UserNotFoundException
}
But, if you had this in your UserNotFoundException catch
return $e; // or anything else (maybe an array containing status and message)
Then It's not possible to write this simple code
if(findById(5)) {
// found and dump it to the view
}
Because, is statement will be true for $e object oe for an array, so you have to check it again, using somrthing like this
$result = findById(5);
if($result && $result->code && $result->code === 0) {
// something according to code
}
Or maybe, something like this
if($result && $result->code) {
// error happened, now determine the code
switch($result->code){
case 0:
// show message
break;
case 1:
// show message
break;
}
}
So, IMO, why, you need to show the user, what error happened in your application, why not just to states, either you got data or you didn't get it. isn't it simple ? Just KISS. This is my opinion only, that's it.