View get unhide automatically in iOS - ios

I have created a view on interface & reducing its height on click of a button with uianimation.Below is the code for the animation
#IBAction func filterClick(sender: AnyObject) {
STF_Search.resignFirstResponder()
UIView.animateWithDuration(0.3, animations:{
if(self.isFilter==false){
self.filterView.frame=CGRectMake(0,117,self.view.frame.size.width,50)
self.STVRA.frame=CGRectMake(0, 168,self.STVRA.frame.size.width,self.STVRA.frame.size.height)
self.isFilter=true
}
else{
self.filterView.frame=CGRectMake(0,117,self.view.frame.size.width,0)
self.tableView.frame=CGRectMake(0, 117,self.STVRA.frame.size.width,self.STVRA.frame.size.height)
self.dateTo="nil"
self.dateFrom="nil"
self.isControlls(true)
self.isFilter=false
}
}
,completion: {(_) -> Void in
if(self.isFilter==true){
self.isControlls(false)
}
else{
self.callRAListWebApi()
}
})
}
Code working perfectly if I don't call the method "self.callRAListWebApi()" on the other hand in above scenario when execution of this methods complete the "filterView" gets into its default height-> 50 which is not supposed as per the logic it should be "0"
("callRAListWebApi" is a method where I am hitting a web api & getting some json response)
I cant understand this unusual behaviour of "filter view" of coming in its original height.I have checked everything there is no clue.

Create autolayout of the view , as the problem is because you are directly changing the frames.

Related

iOS tableView not reloading until click, scroll, or switch tabbar items

I have this problem where (in several places) after executing an API call, the view does not refresh until a user action - like a btn click, tab bar switch, etc occurs. I have a feeling it is related to threading, but I can't seem to figure it out and I am new to iOS programming. I have tried different solutions with DispatchQueue etc, using it, and not using it. Trying to call setNeedsDisplay on the controller view. But no luck yet. The following is an example of code pulled right from one of my tab bar item view controllers:
func getEmployeeUpdates(){
self.showLoader()
APIAdaptor.shared.getEmployeeUpdates(forEmployee: Session.shared.employee, completion: {
(updates:[ScheduleUpdate]?, error:Error?) in
guard error == nil else{
DispatchQueue.main.async {
// self.resetMainScreen()
self.hideLoader();
}
return
}
DispatchQueue.main.async {
self.hideLoader();
self.ScheduleUpdates = updates!
self.tableView.reloadData();
}
})
}
func showLoader(){
NSLayoutConstraint.activate([
activityIndicator!.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor),
activityIndicator!.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor)])
activityIndicator?.startAnimating();
}
func hideLoader(){
print("Hiding");
activityIndicator?.stopAnimating()
}
I have attached two images. The first image is where the api call has finished (confirmed through testing) but the view is not refreshing. The loader is frozen. It should disappear after a call to hideLoader(). the second Image is after a click, or tab bar item switch.
I should also mention that in this example, as well as in other api calls the view will refresh eventually after completing, but only after a significant delay.
If anyone can help I would appreciate it very much!
This was a problem caused by the simulator on Xcode 10.1. If you run into this problem, try updating Xcode, or using a real device.

Swift 3: Checking Internet (Reocurring) viewDidAppear not

Ok, So I am rather new to Swift and I am a little confused about what I am trying to do, or if I am going in the wrong direction. (https://github.com/ashleymills/Reachability.swift)
Here is my viewDidLoad method :
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
checkConnection()
}
I then have a function with the code in from the Reachability GitHub Project:
func checkConnection() {
//declare this property where it won't go out of scope relative to your listener
let reachability = Reachability()!
reachability.whenReachable = { reachability in
// this is called on a background thread, but UI updates must
// be on the main thread, like this:
DispatchQueue.main.async {
if reachability.isReachableViaWiFi {
print("Reachable via WiFi")
} else {
print("Reachable via Cellular")
}
}
}
reachability.whenUnreachable = { reachability in
// this is called on a background thread, but UI updates must
// be on the main thread, like this:
DispatchQueue.main.async {
self.dim(direction: .In, alpha: self.dimLevel, speed: self.dimSpeed)
self.performSegue(withIdentifier: "mainToAlertNoInternet", sender: self)
}
}
do {
try reachability.startNotifier()
} catch {
print("Unable to start notifier")
}
}
As you can see, when there is no internet, this is the code:
self.dim(direction: .In, alpha: self.dimLevel, speed: self.dimSpeed)
self.performSegue(withIdentifier: "mainToAlertNoInternet", sender: self)
The Dim is taken from (http://www.totem.training/swift-ios-tips-tricks-tutorials-blog/ux-chops-dim-the-lights) the mainToAlertNoInternet loads the next view over the current one with transparence so it is an alert style.
So, the second segue has a view and a button on it. Nothing spectacular this is what is loaded when there is no internet:
That try again button is linked to the Exit of the Segue and runs this function in the First View Controller:
#IBAction func unwindFromSecondary(segue: UIStoryboardSegue) {
dim(direction: .Out, speed: dimSpeed)
checkInternetConnection()
}
I added in the function mainToAlertNoInternet so that when they click try again, it will go back to the first segue and run the test again. However, When I click try again, I get this error:
Warning: Attempt to present on whose view is not in the window hierarchy!
Hopefully I have explained enough what I have set up. Now to the Questions:
1) How can I fix this error?
2) Am I doing this the right way or is there a better way?
This is what I want:
I want to check the internet connection the moment the app loads. If there is no connection I want to display the segue like I have been doing. If the user clicks Try gain, I want it to go back to the first controller and run the check again and if still no connection display the segue like it did initially again. I would like this to be a repeating process until there is internet.
Appreciate all your help. Thanks in advance
Edit:
I have added the function call in the ViewDidAppear method like so:
override func viewDidAppear(_ animated: Bool) {
checkInternetConnection()
}
However, it does not run. Also the DIM in the unwindFromSecondary function does not get called when I do this.
Edit 2:
Just added this line into my viewDidAppear:
print("Appeared")
This gets called initially, but then not again.
Question:
How do I get a function to run once everything has loaded again after the unwindSegue?
Any thoughts?
Update 3
Ok, so I have looked at the answers below:
#MarkP Answer works fine. Thank you for that
However, the answer from #iSee has got me thinking maybe I should be going about this a different way.
I have added a Bounty to this post for a detailed answer that can show me and explain how to achieve the following:
In my app. I need to keep making sure that the internet exists (Maybe a Timer) on any view that loads. I would like it so that like the current way, If there is no internet it will pop up the ViewController with this segue:
performSegue(withIdentifier: "mainToAlertNoInernet", sender: self)
It appears that the App Delegate would be the place but I am unsure how to achieve this.
I am new to iOS Development and thus would appreciate some explanation and teaching.
Thank you for your time. It is greatly appreciated.
I presume you are new to iOS development in general.
The warning has nothing to do with your internet connectivity code.
The Warning you are getting is not an error. It is just that, a warning.
The reason you are getting that is well explained in this link and this
To get rid of that warning, you should not call performSegue from viewDidLoad(refer to the above link for more information.
To perform your network checks, it is advisable to use the AppDelegate (gives you a better control over the flow of the app)
All the best :)
EDIT: Please refer to this link here for more information on this. I could easily repost it here but since it is already answered, you can refer to the above link as to why it happens and how to avoid it.
As #iSee has pointed out with the links. This is because the view has not been added to the view hierarchy so you can't move to it. for this self.dismissViewControllerAnimated is needed:
#IBAction func unwindFromSecondary(segue: UIStoryboardSegue) {
dim(direction: .Out, speed: dimSpeed)
self.dismiss(animated: true) {
self.checkInternetConnection()
}
}
I use this in the app delegate ->
func reachablityCode() {
AFNetworkReachabilityManager.sharedManager()
AFNetworkReachabilityManager.sharedManager().startMonitoring()
AFNetworkReachabilityManager.sharedManager().setReachabilityStatusChangeBlock({(status) in
let defaults = NSUserDefaults.standardUserDefaults()
if status == .NotReachable {
defaults.setBool(false, forKey:REACHABLE_KEY)
}
else {
defaults.setBool(false, forKey: REACHABLE_KEY)
}
defaults.synchronize()
})
}
And then this in the base file ->
func isReachable() -> Bool {
return NSUserDefaults.standardUserDefaults().boolForKey(REACHABLE_KEY)
}

Position a button (of Twitter Digits) programmatically in Swift

a newbie question :)
I'm trying to use Twiiter Digits for authentication (by phone number) in my (first) iOS app.
It is easier for my to understand how to position a button programatically when it is a button that i create. but this 1 line of code confuses me.
to embed their action button i just need to add this part of code (see documentation):
override func viewDidLoad() {
let digitsButton = DGTAuthenticateButton(authenticationCompletion: { (session, error) in
// Inspect session/error objects
})
self.view.addSubview(digitsButton)
}
My problem is that the creation of this button is automatically and have a completion handler, so when\where exactly do i have the option to position (format) it?
Thanks.
You can always create your own custom button and use the methods of Digits to perform the same actions. For example :
func didTapButton(sender: AnyObject) {
let digits = Digits.sharedInstance()
digits.authenticateWithCompletion { (session, error) in
// Inspect session/error objects
}
}
Also if you want to continue to customize your Digits button and it's View Controllers , you can find more here here.
It might sound strange but it took me some time to realize i can\need to do it after the completion handler (inside the ViewDidLoad...).
Thanks for Letting me know i can use my own button with Digits.

Change View with NavigationViewController

all this is probably a trivial question, but I have not found a solution to it. I am making an app for Iphone using Swift.
I have a tableview with some strings and if I press a button I want to navigate back to the previous view directly. However, the code after my call
navigationController?.popViewControllerAnimated(true)
is always run, but I want the current activity to stop and go back to the previous view.
The code looks like:
#IBAction func DeletePressed(sender: UIButton) {
let deleteIndices = getIndexToDelete()
navigationController?.popViewControllerAnimated(true)
print("After navigationController")
for index in deleteIndices{
results?.ListResults[yearShownIndex].months[monthShownIndex].day[dayShownIndex].results.removeAtIndex(index)
}
if (results?.ListResults[yearShownIndex].months[monthShownIndex].day[dayShownIndex].results.count == 0){
results?.ListResults[yearShownIndex].months[monthShownIndex].day.removeAtIndex(dayShownIndex)
}
if (results?.ListResults[yearShownIndex].months[monthShownIndex].day.count == 0){
results?.ListResults[yearShownIndex].months.removeAtIndex(monthShownIndex)
}
if (results?.ListResults[yearShownIndex].months.count == 0){
results?.ListResults.removeAtIndex(monthShownIndex)
}
loadView()
}
"After navigationController" is always displayed.
In android you would start a new activity by creating intents to get the desired behaviour, but how does it work on Iphone?
My problem is that I want to be able to go back directly when navigationController.popViewControllerAnimated is called. This is just a toy example to understand how it works so that I can use it in the if-clauses later.
you could simply add a return statement after you pop the viewcontroller:
#IBAction func DeletePressed(sender: UIButton) {
let deleteIndices = getIndexToDelete()
navigationController?.popViewControllerAnimated(true)
return;
[...]
if you don't wants to execute code after "print("After navigationController")" then remove that code
or it is not possible to remove then toggle it when DeletePressed called

UITableView:reloadSectionIndexTitles animated correct way

I am trying to hide the index bar of a UITableView while scrolling.
Therefore I am reloading the section index titles when I start scrolling and when finish. Returning an empty array hides the bar.
My code is:
var showSectionIndexTitles = true
override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
showSectionIndexTitles = false
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.tableView.reloadSectionIndexTitles()
})
}
override func scrollViewWillBeginDecelerating(scrollView: UIScrollView) {
showSectionIndexTitles = true
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.tableView.reloadSectionIndexTitles()
})
}
override func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]! {
if showSectionIndexTitles {
return uniq([UITableViewIndexSearch] + AlphabetUppercase + datamanager.categoryIndexTitles)
} else {
return nil
}
}
This works when using no animations, but I would like to use an animation.
I would prefer an animation where the whole bar moves out to the right when the bar is hidden and move in from the right when the bar is visible
I tried to use UIView:animateWithDuration to test if an animation is possible at all.
What I have noticed:
This basic animation moves/scales in from the left top corner when
visible
When hiding the bar it disappears instantly
My questions:
What is the best way of achieving an animation for indexbar visibility?
What is the best way of achieving the particular animation I mentioned earlier?
Thank you in advance!
EDIT 1:
I just remembered where I have seen this effect before: iOS 8.4 Music App
Apple does the same when you scroll so far that you can only see the title list(UITableView)
EDIT 2:
I filed a bug report to apple suggesting a function for changing visibility of the index bar with a animated parameter. I am going to inform you as soon as I get a response.
Even though #matt already suggested a possible solution in his answer, still if anybody else knows a different convenient way of solving this problem or has also faced this kind of feature in the past I would be glad to hear from you!
What you're trying to do is unsupported. Therefore there is no "best" or "correct" way - whatever you do will be an illegal hack. What I would do is snapshot the index bar, hide the real index bar as you are already doing (i.e. legally and normally), and animate the snapshot.

Resources