Swift MessageKit - Cannot Convert value of type '_?' to expected argument type 'URL?' - swift

I have just begun using MessageKit and have updated my code to 4.2 in swift and have been solving the problems. Yet, I am using the Firebase chat tutorial and have come across problems in the sample code that are throwing errors that aren't visible in the sample project.
Cannot convert value of type '_?' to expected argument type 'URL?'
completion(meta?.downloadURL())

Assuming that your problem is probably the following
storage.child(channelID).child(imageName).putData(data, metadata: metadata) { meta, error in
completion(meta?.downloadURL())
}
Answer, swift 4
storage.child(channelID).child(imageName).putData(data, metadata: metadata) { metaN, error in
// then we check if the metadata and path exist
// if the error was nil, we expect the metadata and path to exist
// therefore if not, we return an error
guard let metadata = metaN, let path = metadata.path else {
completion(nil)
return
}
// now we get the download url using the path
// and the basic reference object (without child paths)
self.getDownloadURL(from: path, completion: completion)
}
private func getDownloadURL(from path: String, completion:#escaping (URL?) -> Void) {
let firebaseStorageUrl = "gs://yourApp-Firebase-Storage.appspot.com"
let storageReference = Storage.storage().reference(forURL: firebaseStorageUrl)
storageReference.child(path).downloadURL { (url, error) in
completion(url)
}
}
Be sure that you have enabled Storage in Firebase and check console errors if fails

Related

xcode symbol navigator for Swift Playground?

While I code along on Swift Talk episode 8
I was stuck for a while on working on Resource structure.
enum HttpMethod<Body> {
case get
case post(Body)
}
struct Resource<A> {
let url: URL
let method: HttpMethod<Data>
let parse: (Data) -> A?
}
extension Resource {
init(url: URL, method: HttpMethod<Any> = . get, parseJSON: #escaping (Any) -> A?) {
self.url = url
self.method = method.map { json in
// TODO: try! is not safe here anymore
return try! JSONSerialization.data(withJSONObject: json, options: [])
}
self.parse = { data in
let json = try? JSONSerialization.jsonObject(with: data, options: [])
return json.flatMap(parseJSON)
}
}
}
Called from:
func pushNotification(token: String) -> Resource<Bool> {
let url = URL(string: "")!
let dictionary = ["token": token]
return Resource(url: url, method: .post(dictionary), parse: { _ in
return true
}) //** my mistake was on this line (see below)
}
Then I got the following error message:
Networking.playground/Pages/Step 10.xcplaygroundpage:118:40: Member 'post' in 'HttpMethod<Data>' produces result of type 'HttpMethod<Body>', but context expects 'HttpMethod<Data>'
Took me a while to realized that I have called the memberwise initializer for the Resource structure: init(url:method:parse:) while I should call the custom initializer: init(url:method:parseJSON:)
(note: the memberwise initializer still exist since we add the custom initializer in extension)
In retrospection, I thought, have I used the Symbol Navigator, I might have found my mistake sooner. But after spending some time on Xcode, I can't figure out how to view symbol navigator for Swift Playground. It's always empty.
I checked on my other Xcode swift project, symbol navigator works properly.
Anybody know how could we get the symbol navigator to work properly in Xcode Swift Playground?

Swift 3 change to NSErrorPointer?

I have code I've been using for SwiftyJSON and I'm trying to update to Swift 3 using XCode 8.0 Beta 3. I'm running into an issue where the compiler doesn't like the argument 'error: &err' as it did before. I've been searching for how to correctly pass an NSErrorPointer but everything I've found says to re-write, leave out the error and throw an error back. Since this isn't my code I'd rather leave it as it is. So what's the correct new way to use an NSErrorPointer?
var err : NSError?
// code to get jsonData from file
let json = JSON(data: jsonData, options: JSONSerialization.ReadingOptions.allowFragments, error: &err)
if err != nil {
// do something with the error
} else {
return json
}
The code above results in compiler error: '&' can only appear immediately in a call argument list. I've tried creating an NSErrorPointer so I can use that instead but I can't find anything on how to initialize one (the type alias declaration is not enough). I've already been to Using Swift with Cocoa and Obj-C, it does not contain the word NSErrorPointer, instead goes over the new way of throwing errors. I've also looked over a couple dozen posts all using the &err so apparently this is new to Swift 3.
Is there anyone out there that's solved this one? What's the answer to using NSErrorPointer?
Thanks,
Mike
That seems to be an error in the Swift 3 branch of SwiftyJSON at
https://github.com/SwiftyJSON/SwiftyJSON/blob/swift3/Source/SwiftyJSON.swift
which defines the init method as
public init(data:Data, options opt: JSONSerialization.ReadingOptions = .allowFragments, error: NSErrorPointer? = nil) {
do {
let object: AnyObject = try JSONSerialization.jsonObject(with: data, options: opt)
self.init(object)
} catch let aError as NSError {
if error != nil {
error??.pointee = aError
}
self.init(NSNull())
}
}
In the Swift 3 that comes with Xcode 8 beta 3, NSErrorPointer is an optional:
public typealias NSErrorPointer = AutoreleasingUnsafeMutablePointer<NSError?>?
as a consequence of
SE-0055: Make unsafe pointer nullability explicit using Optional
Therefore the error parameter should have the type NSErrorPointer,
not NSErrorPointer? (and consequently error??.pointee
changed to error?.pointee).
With these changes the init method becomes
public init(data:Data, options opt: JSONSerialization.ReadingOptions = .allowFragments, error: NSErrorPointer = nil) {
do {
let object: AnyObject = try JSONSerialization.jsonObject(with: data, options: opt)
self.init(object)
} catch let aError as NSError {
if error != nil {
error?.pointee = aError
}
self.init(NSNull())
}
}
and then your code compiles and runs as expected.

Swift: passing params - unexpectedly found nil while unwrapping an Optional value

I'm trying to use Alamofire and passing my parameters to a function I made.
Here's my code:
let msisdn : AnyObject = textFields[0].text!
//let msisdn = textFields[0].text!
let userId = "MyID"
let params = [
"msisidn":msisdn /*as AnyObject*/,
"denom_id":self.selectedGameDetail.Id /*as AnyObject*/,
"game_id":self.selectedGameDetail.GameId /*as AnyObject*/
]
print(params)
showEZLoading(true)
su.postEpins(userId, params: params, completion:{ (result, error) -> Void in
self.hideEZLoading()
if (error != nil){
print("DEBUG: API Response Error")
Utility.displayAlert(self, msg: "There's an errror fetching data from server.")
}
else {
print("DEBUG: API Response Success")
}
})
Everything in selectedGameDetail is a String.
And here's the postEpins function:
func postEpins(msisdn: String, params: [String: AnyObject]?, completion:(result: JSON, error: NSError?) -> Void) {
print("POST EPINS")
}
Doesn't do anything yet. But, whenever the app gets to the function call, I get this:
fatal error: unexpectedly found nil while unwrapping an Optional value
I'm positive it has something to do with the params, but I'm 100% sure. Yes, params has stuff in it. Check below.
What I've tried:
Well, if you see a comment in my code, I've pretty much tried those. And I have no idea what else to do.
For reference, that exact same code works on another part of the app, minus the userID - and I also tried removing that, but it still gave me the above error.
I found this regarding the params:
I noticed that one of the values is an NSTaggedPointerString, whereas everything else is an AnyObject. Is this an issue?

Swift Error: cannot convert of type '()' to specified type 'Bool'

I am New for Swift and I Have Implement File Manager Concept in my Project but it shows the issue and I don't for how to solve this please any body help me for fix the issue.
Here I Post My Code.
class func addSkipBackupAttributeToItemAtPath(filePathString: String) throws -> Bool
{
let URL: NSURL = NSURL.fileURLWithPath(filePathString)
assert(NSFileManager.defaultManager().fileExistsAtPath(URL.path!))
let err: NSError? = nil
let success: Bool = try URL.setResourceValue(Int(true), forKey: NSURLIsExcludedFromBackupKey) //---- This Line Shows the Issue.
if !success {
NSLog("Error excluding %# from backup %#", URL.lastPathComponent!, err!)
}
return success
}
The benefit of the new error handling in Swift 2 is the omission of the quasi-redundant return values Bool / NSError. Therefore setResourceValue does not return a Bool anymore which is the reason of the error message.
As the function is marked as throws I recommend this syntax which just passes the result of setResourceValue
class func addSkipBackupAttributeToItemAtPath(filePathString: String) throws
{
let url = NSURL.fileURLWithPath(filePathString)
assert(NSFileManager.defaultManager().fileExistsAtPath(URL.path!))
try url.setResourceValue(true, forKey: NSURLIsExcludedFromBackupKey)
}
Handle the error in the method which calls addSkipBackupAttributeToItemAtPath
The method setResourceValue is a throw function and does not return a Bool.
Try running your function using a do-catch:
do {
try URL.setResourceValue(Int(true), forKey: NSURLIsExcludedFromBackupKey)
}
catch {
NSLog("Error excluding %# from backup %#", URL.lastPathComponent!, err!)
}

swift OSX: serially generating files using GCD

I am trying to generate .aiff files using NSSpeechSynthesizer.startSpeakingString() and am using GCd using a serial queue as NSSpeechSynthesizer takes in a string and creates an aiff file at a specified NSURL address. I used the standard for loop method for a list of strings in a [String:[String]] but this creates some files which have 0 bytes.
Here is the function to generate the speech:
func createSpeech(type: String, name: String) {
if !NSFileManager.defaultManager().fileExistsAtPath("\(dataPath)\(type)/\(name)/\(name).aiff"){
do{
try NSFileManager().createDirectoryAtPath("\(dataPath)\(type)/\(name)/", withIntermediateDirectories: true, attributes: nil)
let URL = NSURL(fileURLWithPath: "\(dataPath)\(type)/\(name)/\(name).aiff")
print("Attempting to save speech \(name).aiff")
self.synth.startSpeakingString(name, toURL: URL)
}catch{
print("error occured")
}
}
}
And here is the function that traverses the dictionary to create the files:
for key in self.nodeLibrary.keys{
dispatch_sync(GlobalBackgroundQueue){
let type = self.nodeLibrary[key]?.0
let name = key.componentsSeparatedByString("_")[0]
if !speechCheck.contains(name){
mixer.createSpeech(type!, name: name)
}
}
}
The globalBackgroundQueue is an alias to the GCD queue call _T for readability.
The routine runs fine, creates folders and subfolders as required by another external function then synthesizes the speech but in my case I always get one or some which don't load properly, giving 0 bytes or a too small number of bytes which makes the file unuseable.
I read the following post and have been using these GCD methods for a while but I'm not sure where I'm wrong here:
http://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1
Any help greatly appreciated as usual
edit: Updated with completion closure and found possibly a bug
I have created a closure function as below and use it in another helper method which checks for any errors such as sourceFile.length being 0 once loaded. However, all files exhibit a 0 length which is not possible as I checked each file's audio properties using finder's property command+i.
func synthesise(type: String, name: String, completion: (success: Bool)->()) {
if !NSFileManager.defaultManager().fileExistsAtPath("\(dataPath)\(type)/\(name)/\(name).aiff"){
do{
try NSFileManager().createDirectoryAtPath("\(dataPath)\(type)/\(name)/", withIntermediateDirectories: true, attributes: nil)
let URL = NSURL(fileURLWithPath: "\(dataPath)\(type)/\(name)/\(name).aiff")
let success = self.synth.startSpeakingString(name, toURL: URL)
completion(success: success)
}catch{
print("error occured")
}
}
}
func loadSpeech(type: String, name: String){
synthesise(type, name: name, completion: {(success: Bool)->Void in
if success{
print("File \(name) created successfully with return \(self.synthSuccess), checking file integrity")
let URL = NSURL(fileURLWithPath: "\(self.dataPath)\(type)/\(name)/\(name).aiff")
do{
let source = try AVAudioFile(forReading: URL)
print("File has length: \(source.)")
}catch{
print("error loading file")
}
}else{
print("creation unsuccessful, trying again")
self.loadSpeech(type, name: name)
}
})
}
The files are generated with their folders and both the method startSpeakingString->Bool and the delegate function I have in my class which updates the synthSuccess property show true. So I load an AVAudioFile to check its length. All file lengths are 0. Which they are not except for one.
When I say bug, this is from another part of the app where I load an AVAudioEngine and start loading buffers with the frameCount argument set to sourceAudioFile.length which gives a diagnostic error but this is out of context right now.
startSpeakingString(_:toURL:) will start an asynchronous task in the background. Effectively, your code starts a number of asynchronous tasks that run concurrently. This may be the cause of the problem that you experience.
A solution would need to ensure that only one task is active at a time.
The problem with startSpeakingString(_:toURL:) is, that it starts an asynchronous task - but the function itself provides no means to get notified when this task is finished.
However, there's a delegate which you need to setup in order to be notified.
So, your solution will require to define a NSSpeechSynthesizerDelegate.
You may want to create your own helper class that exposes an asynchronous function which has a completion handler:
func exportSpeakingString(string: String, url: NSURL,
completion: (NSURL?, ErrorType?) -> ())
Internally, the class creates an instance of NSSpeechSynthesizer and NSSpeechSynthesizerDelegate and implements the delegate methods accordingly.
To complete the challenge, you need to search for an approach to run several asynchronous functions sequentially. There are already solutions on SO.
Edit:
I setup my own project to either confirm or neglect a possible issue in the NSSpeechSynthesizer system framework. So far, may own tests confirm that NSSpeechSynthesizer works as expected.
However, there are few subtleties worth mentioning:
Ensure you create a valid file URL which you pass as an argument to parameter URL in method startSpeakingString(:toURL:).
Ensure you choose an extension for the output file which is known by NSSpeechSynthesizer and the system frameworks playing this file, for example .aiff. Unfortunately, the documentation is quite lacking here - so I had to trial and error. The list of supported audio file formats by QuickTime may help here. Still, I have no idea how NSSpeechSynthesizer selects the output format.
The following two classes compose a simple easy to use library:
import Foundation
import AppKit
enum SpeechSynthesizerError: ErrorType {
case ErrorActive
case ErrorURL(message: String)
case ErrorUnknown
}
internal class InternalSpeechSynthesizer: NSObject, NSSpeechSynthesizerDelegate {
typealias CompletionFunc = (NSURL?, ErrorType?) -> ()
private let synthesizer = NSSpeechSynthesizer(voice: nil)!
private var _completion: CompletionFunc?
private var _url: NSURL?
override init() {
super.init()
synthesizer.delegate = self
}
// CAUTION: This call is not thread-safe! Ensure that multiple method invocations
// will be called from the same thread!
// Only _one_ task can be active at a time.
internal func synthesize(input: String, output: NSURL, completion: CompletionFunc) {
guard _completion == nil else {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
completion(nil, SpeechSynthesizerError.ErrorActive)
}
return
}
guard output.path != nil else {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
completion(nil, SpeechSynthesizerError.ErrorURL(message: "The URL must be a valid file URL."))
}
return
}
_completion = completion
_url = output
if !synthesizer.startSpeakingString(input, toURL: output) {
fatalError("Could not start speeaking")
}
}
internal func speechSynthesizer(sender: NSSpeechSynthesizer,
willSpeakWord characterRange: NSRange,
ofString string: String)
{
NSLog("willSpeakWord")
}
internal func speechSynthesizer(sender: NSSpeechSynthesizer,
willSpeakPhoneme phonemeOpcode: Int16)
{
NSLog("willSpeakPhoneme")
}
internal func speechSynthesizer(sender: NSSpeechSynthesizer,
didEncounterErrorAtIndex characterIndex: Int,
ofString string: String,
message: String)
{
NSLog("didEncounterErrorAtIndex")
}
internal func speechSynthesizer(sender: NSSpeechSynthesizer,
didFinishSpeaking finishedSpeaking: Bool)
{
assert(self._url != nil)
assert(self._url!.path != nil)
assert(self._completion != nil)
var error: ErrorType?
if !finishedSpeaking {
do {
error = try self.synthesizer.objectForProperty(NSSpeechErrorsProperty) as? NSError
} catch let err {
error = err
}
}
let url: NSURL? = NSFileManager.defaultManager().fileExistsAtPath(self._url!.path!) ? self._url : nil
let completion = self._completion!
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
if url == nil && error == nil {
error = SpeechSynthesizerError.ErrorUnknown
}
completion(url, error)
}
_completion = nil
_url = nil
}
}
public struct SpeechSynthesizer {
public init() {}
private let _synthesizer = InternalSpeechSynthesizer()
public func synthesize(input: String, output: NSURL, completion: (NSURL?, ErrorType?) -> ()) {
_synthesizer.synthesize(input, output: output) { (url, error) in
completion(url, error)
}
}
}
You can use it as shown below:
func testExample() {
let expect = self.expectationWithDescription("future should be fulfilled")
let synth = SpeechSynthesizer()
let url = NSURL(fileURLWithPath: "/Users/me/Documents/speech.aiff")
synth.synthesize("Hello World!", output: url) { (url, error) in
if let url = url {
print("URL: \(url)")
}
if let error = error {
print("Error: \(error)")
}
expect.fulfill()
}
self.waitForExpectationsWithTimeout(1000, handler: nil)
// Test: output file should exist.
}
In the code above, check the result of the call to synth.startSpeakingString(name, toURL: URL), which can return false if the synthesiser could not start speaking. If it fails, find out why, or just retry it.
Plus, add [NSSpeechSynthesiserDelegate][1], and look for the speechSynthesizer:didFinishSpeaking: callbacks there. When the synthesiser thinks it has finished speaking, check the file size. If it is zero, retry the operation.