How do I prevent errors about trying to present a controller on a controller which is already presenting? - uiviewcontroller

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.

Related

how to access a component with url with parameter and without parameter in Angular

I want to implement accessing one component with two url like
first : "helloworld/search"
second : "helloworld/search/tag"
both take me on same page. with both url it should to call two different function
You can listen to router events in the component
`this.router.events.forEach((event: NavigationEvent) => {
if (event instanceof NavigationStart) {
if (event.url.toLowerCase().endsWith("/tag")) {
//one function
}else {
ther function
}
}`

Can I wrap callback function into another to return a value from it?

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.

Angular 6 HttpClient.get Observable does not assign value

I suppose that the answer will be very obvious, but still it evades me. I'm new on working with observables, and now I'm facing issues assigning a value from one. I had success if I define it (this._apps) as an Observable and asking from the view to the service using subscribe (But for my taste is was way convoluted (three levels inside a map just to return another observable with the array and then another function to subscribe the previous to assign the variable and another subscription in the view to finally show the information), inefficient and on top of that I could not get it "right" again). The task is very simple. Given the class Application
export class Application {
name: string;
baseUrl: string;
deprecated: boolean;
}
And the service (just the relevant code)
private _apps: Application[] = [];
constructor(private _http: HttpClient) {
this.getAllApplications().subscribe(apps => {
console.log('Apps subscriber');
this._apps = apps;
console.log('Apps subscriber Ends ' + apps);
},
err => {
console.log(err.status); // 401
console.log(err.error.error); // undefined
console.log(JSON.parse(err.error).error); // unauthorized
});
}
private getAllApplications() {
return this._http.get<Application[]>('http://development:4300/api/v1/apps');
}
From the constructor the function which gets the information from WebAPI is triggered, and the remote call is successful, but the variable this._apps is an empty array if I try to call it from anywhere in the code. I could not determine the type of the parameter "apps" in the subscribe function, but for some reason it cannot be assigned and the best answer given is that it is a function (See my first update) in one of my tries. Currently it returns in the console "[object Object]", but apps[0] gives undefined, so it is an empty Array.
This is the console output, just starting the application:
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
Refreshing apps cache calling http://development:4300/api/v1/atbc-apps
Apps subscriber
Apps subscriber Ends [object Object]
I was trying this solution among many others that I forget (to use the more modern HttpClient instead the Http I used before), so what I'm doing wrong?
Update 1
I changed the constructor to this:
constructor(private _http: HttpClient) {
this.getAllApplications().subscribe(apps => {
console.log('apps length ' + apps.length);
this._apps = apps; // Remember private _apps: Application[] = [];
console.log('Apps subscriber Ends ' + apps.toString);
},
err => {
console.log(err.status); // 401
console.log(err.error.error); // undefined
console.log(JSON.parse(err.error).error); // unauthorized
});
}
and the declaration of the function called into this:
private getAllApplications(): Observable<Application[]> {
// the exactly the same as before
}
And now I got from the console this:
apps length undefined
Apps subscriber Ends
function () {
if (this instanceof Promise) {
return PROMISE_OBJECT_TO_STRING;
}
return originalObjectToString.apply(this, arguments);
}
That is the function I was talking about. Any ideas about why even though there is no errors (nor at compile time, neither at runtime), the returning object is not a real Application array?
Change this line:
private _apps: Application[] = [];
to:
_apps: Application[] = [];
Which will default to making it public. Then this line will see it:
this._apps = apps;
At the end I suppose is a mindset to work with Observables, and I tried to build a kind of cache, so the only way I could do it (let me know if there is a better way) was using the view to fill-out the cache. I could not do it from the service itself because the calling the function from the view is synchronous and to fill out the array is async. So I had to create a public setApplicationCache procedure which is filled out after calling the service from the view, it call the setApplicationCache( Application[] ) function and the rest works because it takes just the cache to do filtering and other operations or use it from other pages w/o calling the database again and again.
This is the code from the first view called (main page)
ngOnInit() {
this._myService.getAllApplications().subscribe(arrObjApps => {
this._myService.setApplicationsCache(arrObjApps)
this.listApps = this._myService.getApplications(true);
});
And the service has this functions:
private _apps: Application[] = [];
getAllApplications(): Observable<Application[]> {
return this._http.get('http://development:4300/api/v1/atbc-apps').pipe(
map( (response: Response) => {
let results = response.json().data.map( app => {
return new Application(app.name, app.baseUrl, app.deprecated);
});
return results;
})
);
}
getApplication(appName: string): Application {
return this._apps.find(app => app.name == appName);
}
getApplications(onlyActives: boolean): Application[] {
if (onlyActives) {
return this._apps.filter(app => app.deprecated == false);
} else {
return this._apps;
}
}
And as I stated the solution should be obvious. Just again the async mindset required to work with observables.

In function call, why parse statement get executed atlast in SWIFT?

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.

Laravel Exception Handling - How to handle exceptions with both API and Html

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.