PFObject subclass gets "Cannot convert value of type 'Match' to expected argument type '#noescape (AnyObject) throws -> Bool'" error - swift

I'm getting the following error when calling indexOf on an array of a subclass of PFObject.
Cannot convert value of type 'Match' to expected argument type
'#noescape (AnyObject) throws -> Bool'
my class:
class Match: PFObject, PFSubclassing {XXXX}
The method where the error is happening:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
//dismiss the image picker
self.dismissViewControllerAnimated(true) { () -> Void in
//wait for the dismissal in case there is an error to show
let recordedVideofileURL = info[UIImagePickerControllerMediaURL] as? NSURL
if let recordedVideofileURL = recordedVideofileURL
{
//upload the file to S3
do
{
let uploadRequest = try S3UploadManager.uploadFile(self.match!.localPathToVideo()!)
self.match!.saveEventually({ (success: Bool, error: NSError?) -> Void in
if (success)
{
// The object has been saved.
self.matchesController.loadObjects()
//set up progress tracking for the upload
uploadRequest.uploadProgress = {[weak self](bytesSent:Int64, totalBytesSent:Int64, totalBytesExpectedToSend:Int64) -> Void in
if let match = self?.match
{
>>>>>>error here var index = self?.matchesController.objects?.indexOf(match)
}
}
}
})
}
catch
{
// TODO: handle error
}
}
}
}
From what i read only, this error happens when the object contained in the array does not conform to the Equatable extension. But PFObject inherits from NSObject which conform to that extension. So I'm at a loss...
Any pointers appreciated

Found the solution. It turns out that the objects method on the PFQueryTableViewController returns [AnyObject], so I need to cast it to [Match]
let objects = self?.matchesController.objects as! [PFObject]
and then it works...
I'm still new at swift and Parse, but this seem wrong for objects method to return [AnyObject]? especially given the comment in the doc
/*!
#abstract The array of instances of <PFObject> that is used as a data source.
*/
public var objects: [AnyObject]? { get }

Related

How can you get the shared instance from AnyClass using a protocol in Swift?

In the past we've used Objective-C to anonymously get the sharedInstance of a class this way:
+ (nullable NSObject *)sharedInstanceForClass:(nonnull Class)aClass
{
// sharedPropertyProvider
NSObject<KVASharedPropertyProvider> *sharedPropertyProvider = [aClass conformsToProtocol:#protocol(KVASharedPropertyProvider)]
? (NSObject<KVASharedPropertyProvider> *)aClass
: nil;
if (sharedPropertyProvider == nil)
{
return nil;
}
// return
return [sharedPropertyProvider.class sharedInstance];
}
It's protocol based. We put this protocol on every class we have with a shared instance where we need to do this.
#objc (KVASharedPropertyProvider)
public protocol KVASharedPropertyProvider: AnyObject
{
#objc (sharedInstance)
static var sharedInstance: AnyObject { get }
}
The above works fine in Objective-C (and when called from Swift). When attempting to write the same equivalent code in Swift, however, there appears to be no way to do it. If you take this specific line(s) of Objective-C code:
NSObject<KVASharedPropertyProvider> *sharedPropertyProvider = [aClass conformsToProtocol:#protocol(KVASharedPropertyProvider)]
? (NSObject<KVASharedPropertyProvider> *)aClass
: nil;
And attempt to convert it to what should be this line of Swift:
let sharedPropertyProvider = aClass as? KVASharedPropertyProvider
... initially it appears to succeed. The compiler just warns you that sharedPropertyProvider isn't be used. But as soon as you attempt to use it like so:
let sharedInstance = sharedPropertyProvider?.sharedInstance
It gives you the compiler warning back on the previous line where you did the cast:
Cast from 'AnyClass' (aka 'AnyObject.Type') to unrelated type
'KVASharedPropertyProvider' always fails
Any ideas? Is Swift simply not capable of casting AnyClass to a protocol in the same way that it could be in Objective-C?
In case you're wondering why we need to do this, it's because we have multiple xcframeworks that need to operate independently, and one xcframework (a core module) needs to optionally get the shared instance of a higher level framework to provide special processing if present (i.e. if installed) but that processing must be initiated from the lower level.
Edit:
It was asked what this code looked like in Swift (which does not work). It looks like this:
static func shared(forClass aClass: AnyClass) -> AnyObject?
{
guard let sharedPropertyProvider = aClass as? KVASharedPropertyProvider else
{
return nil
}
return type(of: sharedPropertyProvider).sharedInstance
}
The above generates the warning:
Cast from 'AnyClass' (aka 'AnyObject.Type') to unrelated type
'KVASharedPropertyProvider' always fails
It was suggested I may need to use KVASharedPropertyProvider.Protocol. That looks like this:
static func shared(forClass aClass: AnyClass) -> AnyObject?
{
guard let sharedPropertyProvider = aClass as? KVASharedPropertyProvider.Protocol else
{
return nil
}
return type(of: sharedPropertyProvider).sharedInstance
}
And that generates the warning:
Cast from 'AnyClass' (aka 'AnyObject.Type') to unrelated type
'KVASharedPropertyProvider.Protocol' always fails
So, I assume you have something like this
protocol SharedProvider {
static var shared: AnyObject { get }
}
class MySharedProvider: SharedProvider {
static var shared: AnyObject = MySharedProvider()
}
If you want to use AnyObject/AnyClass
func sharedInstanceForClass(_ aClass: AnyClass) -> AnyObject? {
return (aClass as? SharedProvider.Type)?.shared
}
Better approach
func sharedInstanceForClass<T: SharedProvider>(_ aClass: T.Type) -> AnyObject {
return T.shared
}

Generic Return Type Based on Class

I'm trying to create factory method on a class that automatically casts to the class it's on.
extension NSObject {
// how can I get the return type to be the current NSObject subclass
// instead of NSObject?
class func create() -> NSObject {
return self.init()
}
// example: create(type: NSArray.self)
class func create<T:NSObject>(type:T.Type) -> T {
return T()
}
}
Example two works, but gets NO advantage from being a class method:
let result = NSArray.create(type: NSArray.self)
But I'd love to be able to just call:
let result = NSArray.create()
without having to cast afterwards. Is there a way to do this in Swift?
You can use the class-level Self for this:
extension NSObject {
class func create() -> Self {
return self.init()
}
}
let array = NSArray.create()
But I don't really see why you would, since you might as well just add an initializer.
The accepted answer does the trick, thanks!
However, I needed this for a case where I wasn't calling the init directly. Instead, I had an object that was of type NSObject and needed a forced downcast
As #Hamish pointed out from this other SO answer, you can use the generic inference on a class method if you're another layer deep (a method called by a class method).
class func create() -> Self {
return createInner()
}
class func createInner<T>() -> T {
// upcasting to NSObject to show that we can downcast
let b = self.init() as NSObject
return b as! T
}
let array = NSArray.create() // gives me an NSArray
An Example with CoreData
I still can't figure out how to get the fetch part to compile, so I'm using an external function still.
import CoreData
// callers use
// try fetch(type: SomeMO.self, moc: moc)
func fetch<T:NSManagedObject>(type:T.Type, moc:NSManagedObjectContext) throws -> [T] {
return try T.fetch(moc: moc) as! [T]
}
extension NSManagedObject {
class func makeOne(moc:NSManagedObjectContext) -> Self {
return makeOneInner(moc: moc)
}
private class func makeOneInner<T>(moc:NSManagedObjectContext) -> T {
let name = "\(self)"
let retVal = NSEntityDescription.insertNewObject(forEntityName: name, into: moc)
return retVal as! T
}
class func fetch(moc:NSManagedObjectContext) throws -> [NSManagedObject] {
let fetchReq:NSFetchRequest<NSManagedObject> = self.fetchRequest() as! NSFetchRequest<NSManagedObject>
let retVal = try moc.fetch(fetchReq) as [NSManagedObject]
return retVal
}
}

Cannot convert value of type '[T]' to expected argument type '[_]'

Every time I try to compile this, I get the error:
Cannot convert value of type '[T]' to expected argument type '[_]'
I'm not really sure why this keeps happening, and I've tried to look up solutions but have found nothing that seemed helpful.
Here's my code:
class FetchRequest <T: NSManagedObject>: NSFetchRequest<NSFetchRequestResult> {
init(entity: NSEntityDescription) {
super.init()
self.entity = entity
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
typealias FetchResult = (success: Bool, objects: [T], error: NSError?)
func fetch <T> (request: FetchRequest<T>,
context: NSManagedObjectContext) -> FetchResult {
do {
let results = try context.fetch(request)
return FetchResult(true, results as! [T], nil)
} catch let error as NSError {
return (false, [], error)
}
}
}
EDIT:
I get the error on this line:
return FetchResult(true, results as! [T], nil)
The problem is that you have two generic placeholder types called T. One at class scope, one at method scope. When you say results as! [T], you're referring to the T at method scope – which is unrelated to the class scope T used in your FetchResult type-alias, which is return type of your fetch method.
Therefore you simply need to rename one of your placeholders, or better yet, eliminate the seemingly redundant request: parameter from the method and just use self instead:
func fetch(inContext context: NSManagedObjectContext) -> FetchResult {
do {
let results = try context.fetch(self)
return (true, results as! [T], nil)
} catch let error as NSError {
return (false, [], error)
}
}
Now you can just simply call fetch(inContext:) on the FetchRequest instance that you want to fetch.

Can't convert PFFile to UIImage using getDataInBackgroundWithBlock

I have an updateCell function which I call within a tableView function.
I'm trying to update the cell and convert the PFFile to a UIImage but I keep getting an error Cannot convert value of type '(NSData?, NSError?) -> Void' to expected argument type 'PFDataResultBlock?'
Confused as I got this from the Parse docs and I can't for the life of my find a solution or where I'm going wrong. Here's my updateUI Function.
func updateUI(venue: Venue) {
venueLabel.text = venue.name
let venueImageFile = venue.image
venueImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
}
}
}
}
and here is the Venue class
class Venue {
private var _name: String!
private var _location: String!
private var _image: PFFile!
var name: String {
return _name
}
var location: String {
return _location
}
var image: PFFile {
return _image
}
init(name: String, location: String, image: PFFile) {
self._name = name
self._location = location
self._image = image
}
}
Any help greatly appreciated. At a point now where I don't know where to turn.
Basically I couldn't find a solution using the getDataInBackgroundWithBlock so I ended up installing Parse UI which explains it perfectly...
PFImageView
Many apps need to display images stored in the Parse Cloud as PFFiles.
However, to load remote images with the built-in UIImageView involves
writing many lines of boilerplate code. PFImageView simplifies this
task by abstracting away these parts.
Once I imported this into my swift file, all I had to do was this:
#IBOutlet weak var venueImage: PFImageView! // Make sure it's this class in the storyboard. It's default would be UIImageView.
func updateUI(venue: Venue) {
venueLabel.text = venue.name
venueImage.file = venue.image
venueImage.loadInBackground()
}
:)

How to use instance method as callback for function which takes only func or literal closure

In "ViewController.swift" I am creating this callback:
func callback(cf:CFNotificationCenter!,
ump:UnsafeMutablePointer<Void>,
cfs:CFString!,
up:UnsafePointer<Void>,
cfd:CFDictionary!) -> Void {
}
Using this observer:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
nil,
self.callback,
"myMESSage",
nil,
CFNotificationSuspensionBehavior.DeliverImmediately)
Results in this compiler error:
"A C function pointer can only be formed from a reference to a 'func' or a literal closure"
The callback is a pointer to a C function, and in Swift you can pass
only a global function or a closure (which does not capture any state),
but not an instance method.
So this does work:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
nil,
{ (_, observer, name, _, _) in
print("received notification: \(name)")
},
"myMessage",
nil,
.DeliverImmediately)
But since the closure cannot capture context, you have no direct reference to self and its properties and instance methods.
For example, you cannot add
self.label.stringValue = "got it"
// error: a C function pointer cannot be formed from a closure that captures context
inside the closure to update the UI when a notification arrived.
There is a solution, but it is a little bit complicated due to
Swift's strict type system.
Similarly as in Swift 2 - UnsafeMutablePointer<Void> to object, you can convert the pointer to
self to a void pointer, pass that as the observer parameter
to the registration, and convert it back to an object pointer in
the callback.
class YourClass {
func callback(name : String) {
print("received notification: \(name)")
}
func registerObserver() {
// Void pointer to `self`:
let observer = UnsafePointer<Void>(Unmanaged.passUnretained(self).toOpaque())
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
observer,
{ (_, observer, name, _, _) -> Void in
// Extract pointer to `self` from void pointer:
let mySelf = Unmanaged<YourClass>.fromOpaque(
COpaquePointer(observer)).takeUnretainedValue()
// Call instance method:
mySelf.callback(name as String)
},
"myMessage",
nil,
.DeliverImmediately)
}
// ...
}
The closure acts as a "trampoline" to the instance method.
The pointer is an unretained reference, therefore you must ensure
that the observer is removed before the object is deallocated.
Update for Swift 3:
class YourClass {
func callback(_ name : String) {
print("received notification: \(name)")
}
func registerObserver() {
// Void pointer to `self`:
let observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
observer,
{ (_, observer, name, _, _) -> Void in
if let observer = observer, let name = name {
// Extract pointer to `self` from void pointer:
let mySelf = Unmanaged<YourClass>.fromOpaque(observer).takeUnretainedValue()
// Call instance method:
mySelf.callback(name.rawValue as String)
}
},
"myMessage" as CFString,
nil,
.deliverImmediately)
}
// ...
}
See also How to cast self to UnsafeMutablePointer<Void> type in swift for more information
about the "bridging" between object pointers and C pointers.
In my case the function I wanted to call from my closure was in the AppDelegate. So I was able to use a delegate to call the function from the closure without using self. Whether this is a good idea or not is something that someone with more experience will have to comment on.
self.pingSocket = CFSocketCreate(kCFAllocatorDefault, AF_INET, SOCK_DGRAM, IPPROTO_ICMP,CFSocketCallBackType.dataCallBack.rawValue, {socket, type, address, data, info in
//type is CFSocketCallBackType
guard let socket = socket, let address = address, let data = data, let info = info else { return }
// stuff deleted, including use of C pointers
let appDelegate = NSApplication.shared.delegate as! AppDelegate
appDelegate.receivedPing(ip: sourceIP, sequence: sequence, id: id)
//}
return
}, &context)
extension AppDelegate: ReceivedPingDelegate {
func receivedPing(ip: UInt32, sequence: UInt16, id: UInt16) {
// stuff deleted
}
}
protocol ReceivedPingDelegate: class {
func receivedPing(ip: UInt32, sequence: UInt16, id: UInt16)
}