Obj-c extension does not work in swift - ios

Trying to use a obj-c extension in my swift project:
UIBezierPath+hello.h
#import <UIKit/UIKit.h>
#interface UIBezierPath(hello)
- (void)hello;
#end
UIBezierPath+hello.m
#import "UIBezierPath+hello.h"
#implementation UIBezierPath(hello)
- (void)hello
{
NSLog (#"hello hello");
}
#end
Bridging-Header.h
#import "UIBezierPath+hello.h"
Swift
let helloPath = UIBezierPath()
helloPath.hello()
It does build and it does sees the hello method. But it does crush:
-[UIBezierPath hello]: unrecognized selector sent to instance 0x7d2116d0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIBezierPath hello]:
unrecognized selector sent to instance 0x7d2116d0'
It seems it does not recognises the implementation.
Probably it does not work because I am dumb:)
Custom obj-c classes work in swift. Only extension give me this problem
Thanks guys

That probably means that you forgot to tick the "Target" checkbox when adding "UIBezierPath+hello.m" to the project, so that the file is not compiled and linked
to the executable.
Adding the "Target Membership" in the File inspector should solve the problem.

Related

Swift-based iOS App Extension using NSExtension

I am experimenting with daemon processes on iOS using the NSExtension private API.
I have been following Ian McDowell's article Multi-Process iOS App Using NSExtension. A sample project is available for download at the end of the article.
My goal is to port this sample project from Objective-C to Swift. It has been simple enough porting the AppDelegate and ViewController to swift for the host application. XCode 9.2 seems to map the NSExtension method declarations in PrivateHeaders.h to Swift for use.
PrivateHeaders.h
#interface NSExtension : NSObject
+ (instancetype)extensionWithIdentifier:(NSString *)identifier error:(NSError **)error;
- (void)beginExtensionRequestWithInputItems:(NSArray *)inputItems completion:(void (^)(NSUUID *requestIdentifier))completion;
- (int)pidForRequestIdentifier:(NSUUID *)requestIdentifier;
- (void)cancelExtensionRequestWithIdentifier:(NSUUID *)requestIdentifier;
- (void)setRequestCancellationBlock:(void (^)(NSUUID *uuid, NSError *error))cancellationBlock;
- (void)setRequestCompletionBlock:(void (^)(NSUUID *uuid, NSArray *extensionItems))completionBlock;
- (void)setRequestInterruptionBlock:(void (^)(NSUUID *uuid))interruptionBlock;
#end
I run into trouble when trying to port the application extension class from Objective-C to Swift. Below is a simplification of the original class and my port:
Extension.h
#import <Foundation/Foundation.h>
#interface Extension : NSObject <NSExtensionRequestHandling>
#end
Extension.m
#import "Extension.h"
#implementation Extension
- (void)beginRequestWithExtensionContext:(NSExtensionContext *)context {
NSLog(#"Beginning request with context: %#", [context description]);
}
#end
Extension.swift
import Foundation
class Extension: NSObject, NSExtensionRequestHandling {
func beginRequest(with context: NSExtensionContext) {
print("Beginning request with context: \(context.description)")
}
}
Attempting to launch the Swift Extension process result in the following error in XCode:
Unable to setup extension context - error: Couldn't communicate with a helper application.
Inspecting the iPhone log via Apple Configurator 2 reveals the following error:
iPhone Extension(CoreFoundation)[366] : *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** - [__NSDictionaryM setObject:forKey:]: object cannot be nil
Is anyone able to provide any additional insight into what might be going wrong here? The swap from Objective-C to Swift seems to be straightforward. I cannot even hit a breakpoint on the Extension application before it seems to crash.
Note: I understand that this likely wouldn't make it past app store review. It will never be going near the app store.

UIImage+ResizeMagick | NSInvalidArgumentException | iOS | Swift

I'm using "UIImage+ResizeMagick" (iOS api by some developer for resizing image written in obj-c) in my swift project, but facing issues and getting the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImage resizedImageByMagick:]: unrecognized selector sent to instance 0x7fe74c2065c0'
I know this error occurs when that function doesn't exists in that particular class or if we pass wrong parameters while calling the function but i don't think it's the case with my code (if i'm not wrong)
This class is written as: "UIImage(ResizeMagick)" and as per my knowledge it's a category so i can use the methods with every UIImage object. I've imported it in my class as #import "UIImage+ResizeMagick.h" and using it as:
UIImage *image = [UIImage imageNamed:#"validate-icon-tick.png"];
image = [image resizedImageByMagick:#"200x200"];
I'm using multiple libraries in my project that are written in obj-c but i'm using bridging header for this purpose. May be the problem with ResizeMagick is because of extensions vs categories difference in obj-c and swift.
Kindly tell me what i'm doing wrong or if is it possible or not. Thanks.
Fixed the issue for using extension (cocopods) in swift.
I've added #import <UIImage-ResizeMagick/UIImage+ResizeMagick.h> in my bridging header file. In controller i've used the methods of this extension as:
let image = oldImage.resizedImageByMagick("200x200")
Extensions vs Categories (in swift and objective-c) are well explained over here:stack overflow post link

MagicalRecord createEntity error in Swift

I have a crash in my Swift project with MagicalRecord - CoreData library : https://github.com/magicalpanda/MagicalRecord
First, I setup MagicalRecord OK in AppDelegate.swift:
MagicalRecord.setupCoreDataStack() //-> This is OK. Don't crash
But, when I want to create a "Contact" entity instance I got a Crash.
My code is the next:
var context = NSManagedObjectContext.MR_contextForCurrentThread() // -> This is OK. Don't crash
var contact = Contact.MR_createInContext(context) // -> CRASH
All compile OK but when the App is running I get the next crash:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an entity named 'MyProject.Contact' in this model.' *** First throw call stack:
(0x27861f77 0x34870c77 0x27590c73 0x9b93d 0x74f28 0x75438 0x2aea6e33 0x2b09acef 0x2b09d19d 0x2b0a79f9 0x2b09ba5b 0x2e106141 0x2782881d 0x27827ae1 0x2782627f 0x27773da1 0x27773bb3 0x2aea0ae7 0x2ae9bc41 0x75ab0 0x75aec 0x34e10aaf)
libc++abi.dylib: terminating with uncaught exception of type NSException
MyProject key is the $(PRODUCT_NAME), how I can fix this?
Kind regards
There is a simple solution to this issue. Just add #objc(ClassName) before the swift NSManagedObject subclass. This allows the Objc side know the right name for the class. Otherwise it will include the module name which is bad in this case because it won't match what you have in your Core Data model. Here's and example from one of my swift projects...
#objc(Plant) public class Plant: NSManagedObject
It seems like MagicalRecord automatically computes the entity name, and does this the wrong way. You can possibly fix this by adding the following code to your Contact class:
class func entityName() -> String {
return "Contact"
}
In Swift, you likely need to set the class for your entity to MyProject.Contact for it to be found automatically though the model. In the Entity inspector on the right of the Entity modeler, you can change the class name there.
The solution of Guido Hendriks with an extension to support all managed objects:
extension NSManagedObject {
class func entityName() -> String {
return NSStringFromClass(self).componentsSeparatedByString(".").last!
}
}
Thank you for the answers. I Think that Guido Hendriks's is a good answer. I tried casademora answer but I didn't got the App work.
Finally I have changed the CoreData classes language (Contact Class) from Swift to Objective-C and now the MagicalRecord library works fine!
Thank you!
I had to deal with the same problem and took me a while to figure out how to...
Thanks #casademora I created the classes as Obj-C ones and imported the headers in bridging-header of my swift project.
Select your .xcdatamodeld file
Editor
Create NSManagedObject Subclass
Select your data model and entities
Save the file as an Objective-C class
Here you go with a nice picture:
And in the prefix header file:
#ifndef DBSwiftTest_Bridging_Header_h
#define DBSwiftTest_Bridging_Header_h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "DKDBManager.h" // My database manager
#import "Runner.h" // My model in this example
#endif
You can create your entity classes in objective-c and exposing them via bridging header to swift. That way crash dissappears
I have the same issue. Here is what i did to solve it:
Step 1: As Guido Hendriks mentioned in his answer
It seems like MagicalRecord automatically computes the entity name, and does this the wrong way. You can possibly fix this by adding the following code to your Contact class"
class func entityName() -> String {
return "Contact"
}
Step 2: In your DataModel, change the Class of the Entity from Contact to ProjectName.Contact

Objective C Category not loaded when added as a dependency

I have a project which has a category for NSString as below
#interface NSString (DataEncoding)
- (NSString *)com_EncryptWithISBN;
#end
#implementation NSString (DataEncoding)
- (NSString *)com_EncryptWithISBN
{
return [self com_EncryptWithKey:[HMHBundleInfoAccess sharedInstance].ISBN];
}
#end
I have this in a different project(B) and it works fine within that project. Now I moved project B to another project A. Now the same code is giving me an error
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSCFString
com_EncryptWithISBN]: unrecognized selector sent to instance
0xd334600'
I doubt whether the category is not linked properly when added as a subproject of Project A.
I have seen this link but no change. Do I need to add project B as a target dependency for Project A?
Any help highly appreciated.
Thanks
Add header NSString+DataEncoding.h (header of your category) to the files where you are using encrypting (where you are performing this selector).

No Visible #interface error in ios

Im getting the following issue in ios how to clear and run the code successfully.
The issue is:
"No visible #interface for 'ViewController' declares the selector 'performSelector:afterDelay:'".
There is no such function performSelector:afterDelay:.
Looking at the docs the only function that includes "performSelector" and "afterDelay" is...
performSelector:withObject:afterDelay:
and
performSelector:withObject:afterDelay:inModes:

Resources