Swift 3: NSURL to URL missing init? - swift

I just used XCode 8 and let it convert my existing project. Now I face the error that there is no init function for new URL without parameters.
class fileObj : NSObject, NSCopying, Comparable {
var URL = NSURL() // initial
...
The new code looks like:
class fileObj : NSObject, NSCopying, Comparable {
var myUrl = Foundation.URL() // initial
...
How should I init the new URL var?

it makes absolutely zero sense to do so, but currently (Swift3, Xcode Version 8.0 (8A218a)) it is working and gives you a totally blank URL object with no purpose at all, as you just asked for.
var myURL: URL = NSURLComponents().url!

Your observation is indeed correct, there is no empty initialiser because this would be an invalid URL, therefore they decided to disallow that.
What I recommend you doing is not initialising the variable at first and making it an optional (URL?). Later in the code, you'll be able to initialise it.

Related

Swift Dictionaries with enum as Identifier not auto completing in completion block

I have a function that returns a completion. The completion has as in parameter a custom class with a dictionary that uses an enum as an identifier.
The problem I am facing is that Xcode does not recognises the type of the variable and does not auto complete when I use it inside of completion block.
My code looks like that
Function
func testFunc (completion:(PrxServiceResponseCallback) ->()){
let responseCallback = PrxServiceResponseCallback()
completion(responseCallback)
}
Class
class PrxServiceResponseCallback:NSObject{
var success = false
var resultCode:Int32 = 0
var response:[PrxResponseAttributes:Any] = [PrxResponseAttributes:Any]()
}
enum PrxResponseAttributes{
case sourceProtocolInfoArray
case sinkProtocolInfoArray
case connectionIDsArray
case connectionInfo
}
Calling the function
testFunc { (testResonse) in
testResonse.response[.]//Not Auto completing
}
The whole idea of making a dictionary with an enum as identifier was to make easier which attributes the dictionary returns but, If I can't auto complete, the idea is more pointless.
Any ideas?
Xcode doesn't give you autocomplete doesn't mean that your code doesn't compile. It just means that Xcode is too stupid to figure things out. I have encountered such situations many times before. It seems to always happen inside closures.
You can just ignore the fact that no autocomplete shows up and type the case name yourself:
testResonse.response[.sourceProtocolInfoArray]
It will compile.
You can also consider creating a struct instead of storing the values in a dictionary. Here's a sample struct (I guessed the types):
struct Response {
let sourceProtocolInfo: [String]
let sinkProtocolInfo: [String]
let connectionIDs: [Int]
let connectionInfo: String
}
If you use var response:[UIColor:Any] = [UIColor:Any]()
it is still not giving auto complete so it is not your issue and you can not do much on it .
If you need auto complete then use PrxResponseAttributes with . (dot)
you can do it like
testResonse.response[PrxResponseAttributes.sourceProtocolInfoArray]
EDIT
Note: It is only happening with implemented closure if you add one property in your PrxServiceResponseCallback class like
var anyValue:Any? {
return response[.connectionInfo] // it is showing completion
}

Swift Dictionary

I'm trying to do this:
var myBeacons: [NSUUID: [Int]] = [NSUUID(UUIDString:"74278BDA-B644-4520-8F0C-720EAF059935"): [1,1]]
but I get the following error:
'[NSUUID: [Int]]' is not convertible to '[NSUUID: [Int]]'
If I do:
var myBeacons2: [String: [Int]] = ["74278BDA-B644-4520-8F0C-720EAF059935": [1,1]]
It works
Did I miss something or does it look like bug ? (I'm using Xcode 7 beta)
Since not every String is a valid UUID the initialiser can fail. Thus the initialiser returns an Optional<NSUUID>. This to encourage code safety.
Depending on your needs you might check that you supplied a valid String for an UUID as follow:
let givenString = "74278BDA-B644-4520-8F0C-720EAF059935"
var myBeacons: [NSUUID: [Int]] = [:]
if let uuid = NSUUID(UUIDString: givenString) {
// Here we are sure that the uuid is valid
myBeacons[uuid] = [1, 1]
}
As Martin points out, NSUUID(UUIDString:) returns an optional. You need to unwrap it:
var myBeacons: = [
NSUUID(UUIDString:"74278BDA-B644-4520-8F0C-720EAF059935")!: [1,1]]
(Note the exclamation point after the call to the NSUUID initializer.)
I tested that under Xcode 6.3.2 and it works. I Haven't tested it under Xcode 7 though.
Edit:
In fact it would be better to use optional binding as outlined in #MatteoPiombo's answer. You should accept his answer since it gives you the most robust solution. (I'm voting for his answer. It's the best answer so far)
convenience init?(UUIDString string: String) returns an optional, try unwrap it as follow:
var myBeacons: [NSUUID: [Int]] = [NSUUID(UUIDString:"74278BDA-B644-4520-8F0C-720EAF059935")!: [1,1]]

Winter 2015 / Lecture 10 - Broken Twitter Package

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
}
...

Global Variable in Swift

I'm creating an iOS 8 app and I want to create a string variable that is accessible to all class. I tried to create global.swift with a string variable in it. I can access the variable but, everytime I initialize the class again using this line let globalVar = global() the value that I've passed returns a nil value. Can someone help me with this. Thank you.
You can put the variable in your AppDelegate, which is a singleton. See this post for how to access the AppDelegate
How do I get a reference to the app delegate in Swift?
Put
public static var global = "String"
in any class. Access via Classname.global.
Just use your Global.swift file and put your global variables and functions inside without any class around it.
//
// Global.swift
//
let myConstant = 5
func myGlobalFunction() {
// ...
}
You can access those variables and functions all around your module.

How do I use objective-c-runtime's object_getIvar & object_setIvar in swift?

Does anybody know why I get BAD_ACCESS on getting & setting of my iVars with the following code ?
class myClass: NSObject {
var model = "Unspecified"
override init() {
super.init()
var key: NSString = "model"
var aClass : AnyClass? = self
var ivar: Ivar = class_getInstanceVariable(aClass, key.UTF8String)
// Set
object_setIvar(aClass, ivar, "R56")
// Get
var value: AnyObject = object_getIvar(aClass, ivar)
}
}
myClass()
You get a bad access because Swift classes do not have traditional iVars anymore (try to grab a Swift class' iVar layout and see for yourself). But Swift classes are also Objective-C objects to the runtime, and there don't appear to be any paths excluding Swift classes in it.
What winds up happening is the runtime hands you a bogus iVar that it truly thinks points to a proper offset in the class definition (probably 0 or thereabouts because it doesn't exist). When you try to get said iVar, the runtime literally derefs you some of the object's bytes and tries to wrap it back up in an Objective-C pointer. Often this data has the tagged bit set unintentionally, and so often maps to tagged classes (in my tests I was reliably getting back a tagged pointer for what the runtime thought was NSMutableData).
Long story short: you can't do it anymore.