I am trying to follow the WWDC20 session "Keep your complications up to date", WWDC20-10049. In trying to follow with the code, I have gotten stuck on the schedule function:
func schedule(_ first: Bool) {
if backgroundTask == nil { //Issue is here
if let url = self.currentWeatherURLForLocation(delegate.currentLocationCoordinate)
{
let bgTask = backgroundURLSession.downloadTask(with: url)
bgTask.earliestBeginDate = Date().addingTimeInterval(first ? 60 : 15*60)
bgTask.countOfBytesClientExpectsToSend = 200
bgTask.countOfBytesClientExpectsToReceive = 1024
bgTask.resume()
backgroundTask = bgTask //Issue is here
}
}
}
}
The issue I am having, since the session only provided snippets, is where the var backgroundTask is defined. This function is declared in the data model, in this case WeatherDataProvider. It is obviously a backgroundURLSession.downloadTask, but it is not identified as self so it should be local to the function, but it is not shown in the snippet. I would expect it to be either sent in as a parameter to the function, or declared in the data model itself. If it is declared there, how is it declared as, according to the talk, it has access to prior background requests as the snippet is checkin to see if there is a background request in the queue so the function doesn't schedule another one. I have searched for the last couple of days, but can find nothing that implements this that I can use to understand where Apple is coming from in this session.
I have checked out this answer, as well as this overview of the session, but I haven't figured this out.
Thanks.
Related
I'm beginner in Swift. I have made a document picker at my task. But I see the documentation it was deprecated to used open var documentPickerMode: UIDocumentPickerMode { get }. While the project in my task runs with minimum deployment of IOS13.
Is there a solution for this feature that can be used on IOS14 and below? Or is this normal, where users need to update IOS?. Forgive me for my ignorance, as I'm new to swift world.
If you look at the docs:
https://developer.apple.com/documentation/uikit/uidocumentpickerviewcontroller
...you'll see the list of four initializers introduced in iOS 14. Each one configures the picker for one specific type of task. There is no need for a "mode" because you cannot not know how your picker is configured, because you configured it. That is the modern architecture.
At the bottom of the same page you will see the three deprecated initializers from iOS 13 and before, each of which takes a "mode" as a parameter. That is what you must use if you insist upon supporting iOS 13, even though they are deprecated in later systems. And that's fine. "Deprecated" means discouraged and superseded; it does not mean illegal. What you're getting is just a warning, not (as your title wrongly stated) an error.
just try this one code
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
guard url.startAccessingSecurityScopedResource() else {
return
}
defer { url.stopAccessingSecurityScopedResource() }
var error: NSError? = nil
NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { (url) in
let _ : [URLResourceKey] = [.nameKey, .isDirectoryKey]
let documentFileData = NSData(contentsOf: (url)) as Data?
pickImageCallback?(nil, url.lastPathComponent, documentFileData)
}
}
I just learned how to use the Result type recently from Sean Allen's video, and I get the idea of using it. However, while I was writing a code, there is a line I don't understand.
The line is 87 in the picture (or this -> guard let self = self else { return } )
At first, I was just doing the same stuff as he did, but I wonder why he add the line in the code. I think he wrote it because the self can be nil and wanted to make sure if the self is not nil and return from the function if it gets nil.
And my question is
when or in which situation the self can be nil?
and
if self gets nil, I think it won't trigger the following line (the one for checking the result), so both of the updateUI function and presentGFAlert... function won't be triggered and nothing shows up on the screen, right?
Its because the closure defines its reference to self as being weak, this means if self is released, the block closure will not prevent self from being destructed, getting a reference count of 0. You can deal with this in the code in the closure, by using all references to self as self?, but this mean self could became nil mid way being executed, by using guard let self = self else { return }, you are saying if execution gets here, I want a strong reference to it, so the object will continue being available until the execution of the of the closure complete, basically all or nothing. This in the past could only happen with multi threaded apps, but with apples new async thread model making cooperative threads more common this is potential more possible.
Your concern is correct. Because getFollowers is an async task, user could go back to previous screen while the task is running. In that case, self could be nil and the return is okay.
On the other hand, to make sure there's no problem with completion block of getFollowers task, self will be captured as strong reference, that could cause memory leak even if user already leave that screen.
He uses weak self to prevent that happens.
func forwardGeocoding(address: String) {
CLGeocoder().geocodeAddressString(address, completionHandler: { (placemarks, error) in
if error != nil {
print(error)
return
}
if placemarks?.count > 0 {
let placemark = placemarks?[0]
let location = placemark?.location
let coordinate = location?.coordinate
print("\nlat: \(coordinate!.latitude), long: \(coordinate!.longitude)")
if placemark?.areasOfInterest?.count > 0 {
let areaOfInterest = placemark!.areasOfInterest![0]
print(areaOfInterest)
} else {
print("No area of interest found.")
}
}
})
var INITIAL_DESTINATION = forwardGeocoding(initialDestination)
var DESIRED_DESTINATION = forwardGeocoding(desiredDestination)
var location = CLLocationCoordinate2DMake(<#T##CLLocationDegrees#>, <#T##CLLocationDegrees#>)
Hello, I am trying to make a mapping app, and am having trouble with this part. What I want to do is be able to separate the INITIAL_DESTINATION latitude and longitudes. I have to do this to create a CLLocationCoordinate2DMake. What I have been trying to do is just use INITIAL_DESTINATION.latitude and INITIAL_DESTINATION.longitude, but I am continuingly facing the same error which is "Value of tuple type "()" has no member "latitude". This is also strange because it does not give that error for INITIAL_DESTINATION.longitude.
Any help or suggestions are greatly appreciated, and thank you for reading and taking the time to respond.
Your function returns nothing, and does nothing with the value returned in the asynchronous completion handler. You need to take the asynchronous result and use it in some fashion.
Try this: Put prints at the end of the function, and inside the completion handler, then run the code. What you'll see is that the function is done before the completion handler runs, because the code inside the block does not run until the remote web site returns an answer across the network. At that time Alamofire hands the result to your code in the completion block.
You'll also need to be aware that there are multiple queues in iOS, and UI changes can only be done on the main queue. The completion block does not run on the main queue, however, so likely to use the information returned from the network you'll need to use the dispatch_async function to call a function in your program and have it execute on the main queue.
i currently developpe an app which request data from a webservice, and one the datas are retrieve, i call a method to create some "swype" card like tinder.
The problem is, i do not success to call my method in the viewDidload, this is my code :
if(success == 1) {
NSLog("Recherche OK");
//Call the swype method
}
This is my method :
func fetchData(int: Int, completion: (()->())?) {
let newCard = Model()
//ttp://thecatapi.com/api/images/get?format=src&type=png
if let url = NSURL(string: "http://test.com/api/images/get?format=src&type=png") {
if let data = NSData(contentsOfURL: url) {
newCard.image = UIImage(data: data)
newCard.content = "test"
newCard.desc = "test"
self.data.append(newCard)
NSLog("fetch new data")
}
Have you got an idea ?
Please read more about getting NSData from a network call. Following is from a Apple Documentation
Do not use this synchronous method to request network-based URLs. For
network-based URLs, this method can block the current thread for tens
of seconds on a slow network, resulting in a poor user experience, and
in iOS, may cause your app to be terminated.
Instead, for non-file URLs, consider using the
dataTaskWithURL:completionHandler: method of the NSSession class. See
URL Loading System Programming Guide for details.
Also I noticed that the url you are showing redirects, so maybe that is the problem. Instead of trying to load it in a UIImage, you can create a UIWebview and show the image there.
You can find Swift related help regarding that in answer here
Trying to follow along and code the Smashtag project while watching the Lecture 10 iTunes video.
When I add the dowloaded Twitter package to my Smashtag project, XCode couldn't find the Tweet class when I made reference to it in the TweetTableViewController.
Because of the problem described above, I added the four classes belonging to the Twitter package individually to the project. XCode found the four classes but adding them in this manner generated 11 compile errors.
I'm using XCode Version 6.3 (6D570) which is subsequent to the iOS 8.3 release.
Has anyone else encountered this issue?
Thank you for reading my question.
~ Lee
Possibly not the most-correct (read: best practice) way to do this, but I'm going to chalk it up to doing what it takes to finish the course.
I just went through the list of compile errors and changed the relevant properties to var instead of let. Constants can't be changed and in the new version of Swift they can only be instantiated once. So for the sake of not rewriting too much code, I chose to make certain properties vars instead of lets.
Other bugs I found following the iTunes U course:
The named ‘handler:’ argument needs the name explicitly in a few places.
The simulator will show "TwitterRequest: Couldn\'t discover Twitter account type.” until you go to Settings (inside the simulator) and set the Twitter account. At this point I had to reboot the device, as the call is made in the ViewDidLoad, and thus is only called the first time the view loads. (Alternatively, you could close out the app from the app switcher in the simulator and relaunch that way.)
Here is a gist with corrected code that you can use as a Twitter package that will work with the course and has fixes for the aforementioned bugs, minus the Twitter account setting:
https://gist.github.com/mattpetters/ccf87678ccce0c354398
As Christian R. Jimenez said, "I went to Settings in the Simulated iphone and add my Twitter Account. And everything works perfect." in http://cs193p.m2m.at/cs193p-lecture-10-table-view-winter-2015/. I just added my Twitter Account and tested it, it works!
I had similar problems with the Twitter packages using Swift 2.0 and Xcode 7.2
I'm very new to Swift, so there is a good chance the changes I made are not best practices, but the updated files do work: https://gist.github.com/awaxman11/9c48c0b4c622bffb879f.
For the most part I used Xcode's suggested changes. The two larger changes I made were:
In Tweet.swift I updated the the IndexedKeyword struct's init method to use advanceBy() instead of advance()
In TwitterRequest.swift I updated the signature of NSJSONSerialization to conform to the new error handling system
I've just had a big session fixing the Twitter package files for this same version of Xcode.
It seems that what has broken is that in this version of Swift, constants ('let x...') may only be initialized once, so if a constant is given a value in the declaration ('let x = false'), it may not be changed in the init() function. The Twitter package gives some constants initial values, but then changes the values in the init() function.
My solution to this was to follow the styles suggested in the current version of the Apple Swift language book: declare (many of) the constants as implicitly unwrapped optionals, unconditionally assign a value to them in the init() function (which value may be nil), then test whether any of them are nil, and, if so, return nil from init().
See https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html, click "On This Page" and choose "Failable Initializers"
Also, in TwitterRequest.swift, I needed to add the parameter name 'handler:' in a couple of calls to performTwitterRequest(request, handler: handler).
As an example of constant initialization, in MediaItem.swift:
<< Original Code >>
...
public let aspectRatio: Double = 0
...
init?(data: NSDictionary?) {
var valid = false
if let urlString = data?.valueForKeyPath(TwitterKey.MediaURL) as? NSString {
if let url = NSURL(string: urlString) {
self.url = url
let h = data?.valueForKeyPath(TwitterKey.Height) as? NSNumber
let w = data?.valueForKeyPath(TwitterKey.Width) as? NSNumber
if h != nil && w != nil && h?.doubleValue != 0 {
aspectRatio = w!.doubleValue / h!.doubleValue
valid = true
}
}
}
if !valid {
return nil
}
}
...
<< Updated code >>
...
public let aspectRatio: Double
...
init?(data: NSDictionary?) {
if let urlString = data?.valueForKeyPath(TwitterKey.MediaURL) as? NSString {
if let url = NSURL(string: urlString as String) {
self.url = url
let h = data?.valueForKeyPath(TwitterKey.Height) as? NSNumber
let w = data?.valueForKeyPath(TwitterKey.Width) as? NSNumber
if h != nil && w != nil && h?.doubleValue != 0 {
aspectRatio = w!.doubleValue / h!.doubleValue
return
}
}
}
return nil
}
...