iOS 8 Today Widget shows up blank for a few seconds - ios

My today widget takes between 0 and 5 seconds to show up after pulling down the notification center. As soon as I move up my notification center a bit, my widget disappears again.
Once the widget is visible, everything works fine.
What am I missing?
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
if (self.locationManager.respondsToSelector(Selector("requestWhenInUseAuthorization"))){
self.locationManager.requestWhenInUseAuthorization()
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
self.locationManager.startUpdatingLocation()
imageViewCheck.layer.cornerRadius = 5.0
self.getLocation()
}
func getLocation() -> Bool{
var test = self.locationManager.location
if test != currentLocation {
currentLocation = test
return true
} else {
return false
}
}
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)!) {
var newLocation = self.getLocation()
if (newLocation) {
completionHandler(NCUpdateResult.NewData)
} else {
completionHandler(NCUpdateResult.NoData)
}
}

Solved:
After hours of not finding anything I decided to delete my whole Code and put it back together piece by piece. Unfortunately the problem was still there without any code left. After checking all Layout constraints without finding any error I deleted the widget and added a new one.
And guess what? It worked...
It seemes like xCode didn't like my experimenting with the layout and had something messed up where I could not fix it.
After adding the new widget and reproducing my old one with the exact same constraints and code everything worked perfectly.

Related

Create new event in CalendarKit

In my app, I'm trying to add ability to create a new event with CalendarKit when I press an empty space, but I can't find how to do that.
I know it's possible because you can do it in the demo app:
I've tried adding this to my app's code:
override func create(event: EventDescriptor, animated: Bool = false) {
self.events.append(event) // self.events is my events data source
}
But it didn't worked, in fact, it doesn't even get called when I long press an empty space.
I also tried to look in the source code, but I found nothing. How can I do that? thanks in advance
override func dayView(dayView: DayView, didLongPressTimelineAt date: Date) {
let newEvent = Event()
newEvent.startDate = date
newEvent.endDate = date.addingTimeInterval(3600)
// Customize your event...
newEvent.text = randomName() // A function that generates a new random name that haven't been used before.
self.create(event: newEvent)
}
override func create(event: EventDescriptor, animated: Bool = false) {
super.create(event: event, animated: animated)
self.events.append(event)
}
override func dayView(dayView: DayView, didUpdate event: EventDescriptor) {
for (index, eventFromList) in events.enumerated() {
if eventFromList.text == event.text {
events[index] = event
}
}
self.endEventEditing()
self.reloadData()
}
Please make sure that every Event have it's own unique name, otherwise it won't work

mapKit Apple: Bug with places' names and no focus map on user

I try to go from VC1 on VC2 with map by button1 through segue, and It has to focus pin on my location in the center of map and it has bug. it doesn't focus on user, but if I press button 2, go back and press button 1, it focuses on user. And I can't understand where is I need to fix it.
And the last bug: if I set huge value of regionInMeters, for e.g. 10000m, and I zoom, it shows names of places, streets with bug(image) in both cases, when I try to use this method with user. If I set low - 500, it shows correct close in these cases, but just location around user, if I switch there in another city and zoom in, it still will have this bug. And the same story with focus on place. On huge height - country names, cities, rivers are correct everywhere .
let annotationIdentifire = "annotationIdentifire"
let locationManager = CLLocationManager()
let regionInMeters = 500.00
var incomeSegueIdentifire = ""
override func viewDidLoad() {
super.viewDidLoad()
addressLabel.text = ""
mapView.delegate = self
setupMapView()
checkLocationServices()
}
private func checkLocationServices(){
if CLLocationManager.locationServicesEnabled() {
setupLocationManager()
checkLocationAuthorization()
} else{...}
private func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
mapView.showsUserLocation = true
if incomeSegueIdentifire == "getAddress" { showUserLocation() }
break
//other cases
}
Also I have another button2 with segue on VC1 which opens VC2 with map and it focuses on place, with address, which I set, and in this case I have button3 on map, which focuses on me correct:
#IBAction func centerViewInUserLocation() {
showUserLocation()
}
There is method which I use to focus on user.
private func showUserLocation() {
if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion(center: location,
latitudinalMeters: regionInMeters,
longitudinalMeters: regionInMeters)
mapView.setRegion(region, animated: true)
}
}
Value of incomeSegueIdentifire I set in another class
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let identifire = segue.identifier, let mapVC = segue.destination as? MapViewController else { return }
mapVC.incomeSegueIdentifire = identifire
}
I din't find how to fix bug with places' names, but I fixed the main bug(when open map by segue it has to focus on user, but it's not).
I get mistake:Could not retrieve region info. And tried to find the answer for this case, but didn't find. Found couple cases with answers about this mistake and there said, that code is OK, but still mistake, and the main answer/advice - try to run it on your real device, may be it's correct, I don't have iphone/ipad. But for simulator I fixed it by calling this method asynchronously with delay, and it works for me)
private func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
mapView.showsUserLocation = true
if incomeSegueIdentifire == "getAddress" { DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.showUserLocation()
}
}
//other cases
}
}
But still, if you have any ideas with these issues, I'll be glad to know))

UIViewController dismiss issue

I want to wait until dismiss animation completes but I don't want to use many blocks in my code, so I wrote this function in UIViewController extension (almost like this worked several years ago for me):
func dismissAnimated() {
var comleted: Bool = false
self.dismiss(animated: true) {
comleted = true
}
while !comleted {
RunLoop.current.run(mode: RunLoop.Mode.common, before: Date.distantFuture)
}
}
so now instead of:
viewController.dismiss(animated: true) {
// code after completion
}
I was supposed to write:
viewController.dismissAnimated()
// code after completion
But it doesn't dismiss view controller and doesn't enter into completion block.
I tried different RunLoop modes, tried different dates, tried inserting RunLoop.current.run into while condition, it didn't work. Any ideas how to accomplish this?
Edit:
And it worked on iOS 9 or something like this (may be with some code changes, because I can't find my source code). I start RunLoop.current.run to avoid blocking main thread. For instance, if I put completed = true in DispatchQue.main.asyncAfter , it will work, the issue is with dismiss
I tried again because I was curious and this solution actually works for me:
#objc private func dismissTapped() {
let dismissalTime = dismissAnimated()
print("Dismissal took: %ld", abs(dismissalTime))
}
private func dismissAnimated() -> TimeInterval {
let startDate = Date()
var completed = false
self.dismiss(animated: true) {
completed = true
}
while !completed {
RunLoop.current.run(mode: .default, before: .distantFuture)
}
return startDate.timeIntervalSinceNow
}
iOS 12.1.2 | Swift 4.2
It doesn't dismiss because your while !completed loop has stalled the main thread and the UI update happens on the main thread. What is wrong with running whatever code you need to run inside the dismiss completion closure?
self.dismiss(animated: true) {
runSomeCode()
}
If it's really just about not using blocks maybe this may be a solution?
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if self.navigationController?.isBeingDismissed ?? self.isBeingDismissed {
print("Dismissal completed...")
}
}

Launch saved state at startup of app (swift)

what the app does so far is that users go through an array of strings by clicking a button, when they leave and remove the app from multitasking it saves where they were in the array. But when you startup the app you get stuck at the first String but you have to press the button called showFunFact() to get where you left off. I would like the current one to come at startup
Here's the code:
let TechnologyfactBook = TechFactBook()
var TechfactIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func showFunFact() {
if (UIApplication.sharedApplication().applicationIconBadgeNumber != 0){
UIApplication.sharedApplication().applicationIconBadgeNumber = 0
}
if (TechfactIndex >= TechnologyfactBook.TechfactsArray.count) {
self.TechfactIndex = 0
}
TechfactIndex = NSUserDefaults.standardUserDefaults().integerForKey("ByteLocation")
TechByteLabel.text = TechnologyfactBook.TechfactsArray[TechfactIndex]
TechfactIndex++
NSUserDefaults.standardUserDefaults().setInteger(TechfactIndex, forKey: "ByteLocation")
NSUserDefaults.standardUserDefaults().synchronize()
}
Just add the code that loads the last location into the viewDidLoad. What the code does is first it checks if the user's last location is greater than the starting position, which I assume is 0. Once it checks this, it will assign the text value to the value that the user last had.
override func viewDidLoad() {
super.viewDidLoad()
//Checks if the value that is saved into the app is greater than the
//starting position the app first starts at (assuming index 0?)
if NSUserDefaults.standardUserDefaults().integerForKey("ByteLocation") != 0 {
TechByteLabel.text = TechnologyfactBook.TechfactsArray[TechfactIndex]
} else {
//The code that first displays the values if the user
//just started the app
}
}

iOS label does not update text with function in Swift [duplicate]

This question already has answers here:
update text field ui in swift ios
(2 answers)
Closed 8 years ago.
This seemingly simple issue is driving me crazy... I am playing around with SwiftyJSON to grab remote data and here is a snippet from my ViewController class in Swift:
override func viewDidLoad() {
super.viewDidLoad()
self.statusLabel.text = "welcome"
RemoteDataManager.getStatusUpdateFromURL { (statusData) -> Void in
let json = JSON(data: statusData)
self.statusLabel.text = "this does not work"
self.statusLabel.text = self.getMostRecentStatusUpdate(json) // also does not work
}
}
The statusLabel text is set to "welcome" but does not change afterwards. Funny though, anything I put inside func getMostRecentStatusUpdate(_:) with println() is printed to the console correctly, even if it comes from the remote json source (i.e. I know that this function works). My problem is that I cannot get the text printed to a UILabel instead of the console. I do not get any error messages.
I am not yet really familiar with the sort of Swift function like MyClass.myMethod { (myData) -> Void in .... } and I don't understand what's going wrong here. Any ideas?
UIKit is not thread safe and should only be updated from the main thread. Downloads are done on background thread, and you cannot update UI from there. Try:
override func viewDidLoad() {
super.viewDidLoad()
self.statusLabel.text = "welcome"
RemoteDataManager.getStatusUpdateFromURL { (statusData) -> Void in
let json = JSON(data: statusData)
dispatch_async(dispatch_get_main_queue()) {
self.statusLabel.text = "this does not work"
self.statusLabel.text = self.getMostRecentStatusUpdate(json) // also does not work
}
}
}

Resources