Missing URL(from: NSPasteboard) and Swift 3 - xcode

I have the following function:
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
let pasteboard = sender.draggingPasteboard()
let fileURL = URL(from: pasteboard)
// Does something
}
I am getting the following error at "URL(from: pasteboard)"
Argument labels '(from:)' do not match any available overloads
From what I can tell NSURL has the following method.
init?(from pasteBoard: NSPasteboard)
I don't know what I am doing wrong?

Short answer is URL is not the same as NSURL. The changes to Swift 3 didn't just remove the NS, to make things easier to read, but implemented there own simplistic version of NSURL. When on an Apple device it will secretly use NSURL.
To fix it I changed my code to use this:
let fileURL = NSURL(from: pasteboard) as? URL
More information about the removal of NS can be found here: https://github.com/apple/swift-evolution/blob/master/proposals/0086-drop-foundation-ns.md
If you want to view the source code it is found here: https://github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/URL.swift

Related

Swift 4.2.1 requesting JSON with Xcode 10.1

My code:
let cgpurl = URL(string: "https://api.coingecko.com/api/v3/ping")!
let task = URLSession.shared.dataTask(with: cgpurl) { (Data, URLResponse, Error) in
if let data = Data, let string = String(data: data, encoding: .utf8) {
let CGPing = string } ; resume() }
The problem is with the 2nd use of "cgpurl". I've tried changing case to no effect. The error I'm getting is, "Cannot use instance member 'cgpurl' within property initializer; property initializers run before 'self' is available". Ok... but I can't even replace cgpurl with the actual link? Then I get the error message "Ambiguous reference to member 'dataTask(with:completionHandler:)'" I realize this release of swift was supposed to be "small" & just to "fix errors" but I've not been able to find any current documentation on this release. I'm using swift 4.2.1 with Xcode 10.1
This code was taken directly from a teaching manual for Swift 4.2
No, it wasn't. The code you have was never right, in Swift 4.2 or any other version of Swift. You have blindly copied and pasted perhaps, without looking at the overall context.
The problem is that the code, as you have it, is sitting "loose" at the top of your view controller or other class declaration, perhaps something along these lines:
class MyViewController : UIViewController {
let cgpurl = // ...
let task = // ...
}
That's wrong. The most basic rule of Swift programming is that executable code can exist only in a function. For example:
class MyViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let cgpurl = // ...
let task = // ...
}
}
That may not solve all your issues, but at least you'll get past the most basic mistake you're making and the "Cannot use instance member" compile error will go away.

CloudKit Get actual Object from Record ID in OSX

I am trying to use CKSubscription to subscribe to changes. I am following Apple's docs which seems to be very general and incomplete.
Link to Apple Doc
I have got the point of getting Record ID sent to my app via the didReceiveRemoteNotification method in AppDelegate and I have got my Record Id: using this code:
func application(application: NSApplication, didReceiveRemoteNotification userInfo: [String : AnyObject]) {
let cknNotification = CKNotification(fromRemoteNotificationDictionary: userInfo as! [String:NSObject])
if cknNotification.notificationType == .Query,
let queryNotification = cknNotification as? CKQueryNotification {
let recordId = queryNotification.recordID
print(recordId)
}
How do I convert the CKNotification into the Actual Object I stores in Cloudkit? Do I need to perform another fetch or is the data contained in the CKNotification that I just need to Cast.
Looks like I worked it out.
The Notification only lets you know that they have changed. You need to do the work to pull the new records and update them. ( Makes sense really)
privateCloudDatabase().fetchRecordWithID(recordId!, completionHandler: { (recordfetched, error) in
//Check the Record Type if multiple.. I only have one type.
let myRecordType = recordfetched?.recordType
let myObject = mySuperObject(record: recordfetched!)
print("done")
})
// I should probably add more optional checking - but above just illustrates the solution and how simple it is to get.

NSCache() is not working properly

I think I am tired of NSCache(). Could not understand what's the problem behind this. Trying to save an array of [AnyObject] to NSCahce(), which I have done using this following line of code.
NSCache().setObject(data, forKey: "News")
And tried to get it back using this way.
if let news = NSCache()("News") as? [AnyObject]
{
}
else
{
// I am always here :)
}
So I was thinking what's the problem with this. After searching a bit in Google I could see that setting totalCostLimit and countLimit will help you solve this problem. So I have set it like this.
NSCache().totalCostLimit = 50000
NSCache().countLimit = 50000
After setting this also, it was not working. So I thought of running this code in main thread, which I have done like this.
dispatch_async(dispatch_get_main_queue()) {
NSCache().setObject(data, forKey: "News")
}
Still it returned nil. Now last but not the least I have created one global instance of NSCache() and called all these operations using that instance. Well, doing like that also didn't give the expected result. It always gave me nil.
What's happening here? I know that NSCache() can store AnyObject values. I am saving lot of images in the same project without any problem, when I am trying to save this it returns nil.
Well this AnyObject contains some custom classes. Is that can be a problem? If yes, how will I save it locally without using CoreData or NSUserdefaults.
How I created an instance globally and accessed these. Created one instance of NSCache in the AppDelegate.swift file but outside of AppDelegate class
let mainCache = NSCache()
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(aNotification: NSNotification)
{
mainCache.totalCostLimit = 50000
mainCache.countLimit = 50000
}
}
Later I have used it like this.
mainCache.setObject(data, forKey: "News")
And getting the data back like this.
if let news = mainCache.objectForKey("News") as? [AnyObject]
{
}
else
{
// Always here :)
}
When you write NSCache() you are creating a new NSCache instance. You're doing this on just about every line.
What you need to do is create one instance, let myCache = NSCache(), and then reuse it: myCache.setObject(data, forKey: "News").

'#selector' refers to a method that is not exposed to Objective-C

The new Xcode 7.3 passing the parameter via addTarget usually works for me but in this case it's throwing the error in the title. Any ideas? It throws another when I try to change it to #objc
Thank you!
cell.commentButton.addTarget(self, action: #selector(FeedViewController.didTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)
The selector it's calling
func didTapCommentButton(post: Post) {
}
In my case the function of the selector was private. Once I removed the private the error was gone. Same goes for fileprivate.
In Swift 4
You will need to add #objc to the function declaration. Until swift 4 this was implicitly inferred.
You need to use the #objc attribute on didTapCommentButton(_:) to use it with #selector.
You say you did that but you got another error. My guess is that the new error is that Post is not a type that is compatible with Objective-C. You can only expose a method to Objective-C if all of its argument types, and its return type, are compatible with Objective-C.
You could fix that by making Post a subclass of NSObject, but that's not going to matter, because the argument to didTapCommentButton(_:) will not be a Post anyway. The argument to an action function is the sender of the action, and that sender will be commentButton, which is presumably a UIButton. You should declare didTapCommentButton like this:
#objc func didTapCommentButton(sender: UIButton) {
// ...
}
You'll then face the problem of getting the Post corresponding to the tapped button. There are multiple ways to get it. Here's one.
I gather (since your code says cell.commentButton) that you're setting up a table view (or a collection view). And since your cell has a non-standard property named commentButton, I assume it's a custom UITableViewCell subclass. So let's assume your cell is a PostCell declared like this:
class PostCell: UITableViewCell {
#IBOutlet var commentButton: UIButton?
var post: Post?
// other stuff...
}
Then you can walk up the view hierarchy from the button to find the PostCell, and get the post from it:
#objc func didTapCommentButton(sender: UIButton) {
var ancestor = sender.superview
while ancestor != nil && !(ancestor! is PostCell) {
ancestor = view.superview
}
guard let cell = ancestor as? PostCell,
post = cell.post
else { return }
// Do something with post here
}
Try having the selector point to a wrapper function, which in turn calls your delegate function. That worked for me.
cell.commentButton.addTarget(self, action: #selector(wrapperForDidTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)
-
func wrapperForDidTapCommentButton(post: Post) {
FeedViewController.didTapCommentButton(post)
}
As you know selector[About] says that Objective-C runtime[About] should be used. Declarations that are marked as private or fileprivate are not exposed to the Objective-C runtime by default. That is why you have two variants:
Mark your private or fileprivate method declaration by #objc[About]
Use internal, public, open method access modifier[About]

'AppDelegate' does not have a member named 'managedObjectContext'

I have been following a guide on how to have values using CoreData in swift. I have been having the error 'AppDelegate' does not have a member named 'managedObjectContext'. The guide was using the Beta version of XCode, has this been changed and any ideas on how I can fix my problem.
#IBAction func saveButtonPushed(sender: AnyObject) {
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext
var newName = NSEntityDescription.insertNewObjectForEntityForName("SavedFills", inManagedObjectContext: context) as NSManagedObject
newName.setValue("Test", forKey: "name")
newName.setValue("Test2", forKey: "password")
context.save(nil)
println(newName)
println("Saved")
}
No, it shouldn't have changed at all. The error says it. There is no managedObjectContext in your AppDelegate.swift file. If you follow a tutorial, there should be a managedObjectContext in your AppDelegate.swift file already. Maybe you've missed this step. If this isn't the case, you should either add one by yourself or copy it.
If you want to get a 'standard' managedObjectContext just create a new Swift-Project and check the Use Core Data checkbox during the creation:
New -> File->Project-> Master-Detailview Application-> Use Core Data
If you are new to CoreData and Swift, try the tutorial from raywenderlich about Swift and CoreData. It's easy and nicely written.

Resources