Subclasssing NSFont - objective-c

Trying to write some common libraries that work between iOS and OS X. In order to not clutter up the apps by putting tons of #if TARGET_OS_IPHONE in the code I figured I would be able to subclass both UIFont and NSFont using a common .h and just use separate .m files for each build. So I have the following subclass structure MyFont.h and MyFont_iOS.m and MyFont_OSX.m. Each target includes the appropriate .m file. Works fine on iOS but when executing on OSX I get an EXC_BAD_ACCCES creating the font object with a line like
MyFont *myFont = [MyFont fontWithName:#"Arial" size:132.0];
Can I not subclass NSFont?
Here's my basic code sample for the NSFont subclass (note as of this time I have no specialized code in the subclass. This is just a basic subclass)
MyFont.h
#if TARGET_OS_IPHONE
#interface MyFont : UIFont
#else
#interface MyFont : NSFont
#endif
#end
MyFont_iOS.m
#import "MyFont.h"
#implementation MyFont
#end
MyFont_OSX.m
#import "MyFont.h"
#implementation MyFont
#end
Attempted Use of the sub classed font (in iOS App - Works Fine!)
#import "MyFont.h"
...
MyFont *myFont = [MyFont fontWithName:#"Arial" size:45.0];
Attempted Use of the sub classed font (in OS X App - Crashes!)
#import "MyFont.h"
...
MyFont *myFont = [MyFont fontWithName:#"Arial" size:132.0];
FYI - I'm also getting the warning on this line
incompatible pointer types initializing 'MyFont *' with an expression of type 'NSFont *'
So I'm definitely doing something wrong but just don't understand why it's forcing me to use NSFont but works fine on UIFont.
Thanks for any guidance!

fontWithName returns a NSFont/UIFont - fixed. IT cant be subclassed
Even if it works, it is not defined behaviour
what you can do is have a wrapper that HOLDS the platform specific font
e.g.
#implementation MyFont {
PlatformSpecificFont *_font
}
+ (instancetype)fontWithName:... {
_font = [PlatformSpecificFont fontWithName:...];
return self;
}

Wrapper is a good way to do this. An alternative: Depending on the target, either
#define MyFont NSFont
or
#define MyFont UIFont
And where both require different code, you can add extensions to the class.

Related

Appcelerator iOS Module with OpenCV - OpenCV's camera won't open

So, I am developing an Appcelerator iOS Module which uses OpenCV to do some image processing with the camera.
The thing is, the camera won't open at all. I read the official OpenCV example, followed the steps (of course, had to adapt things to be used as an Appc Module), also followed the iOSModuleQuickStart from the Appcelerator Wiki. I thought I did it right, except that it just doesn't work.
This is my .h View class from the Module:
#import "TiUIView.h"
#import <Foundation/Foundation.h>
#import <opencv2/videoio/cap_ios.h>
#import <UIKit/UIKit.h>
using namespace cv;
#interface ComIosopencvmoduleTestView : TiUIView<CvPhotoCameraDelegate>
{
UIImageView *imageView;
CvPhotoCamera *photoCamera;
}
#property (nonatomic, retain) CvPhotoCamera* photoCamera;
#end
This is the implementation of it (.mm):
#import "ComIosopencvmoduleTestView.h"
#import "TiUtils.h"
// some other imports....
#implementation ComIosopencvmoduleTestView
#synthesize photoCamera;
#pragma mark - UI Actions
- (void)initializeState
{
self.photoCamera = [[CvPhotoCamera alloc] initWithParentView:imageView];
self.photoCamera.delegate = self;
self.photoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack;
self.photoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetPhoto;
self.photoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset352x288;
self.photoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
[self.photoCamera start];
// The instantiation and the call to start method, should do the trick, but it doesn't
}
#end
And, this is how I call it on JS, from Appcelerator Studio:
var VWindow = Ti.UI.createWindow({});
var VView = VItire.createView({});
var VItire = require('com.iosopencvmodule.test');
VWindow.add(VView);
VWindow.open();
This code, according to what I understood from both Tutorials, OpenCV and Appcelerator, should be enough to open the Camera as the App is launched.
Please, what could possibly be wrong? I am going mad with this. Thanks in advance!
Please help!

Why is a specific Swift class not visible to Objective-C?

All
Xcode 10.3 and Swift 5.0
I have a complex project with 3 targets ("Name", "Name Test" and "Name Local")
I have set all interoperability headers between Swift and Objective-C, including the Name-Bridging-Header.h, the Objc Preprocessor Macros to import the Name-Swift.h, Name_Test-Swift.h or Name_Local-Swift.h selectively
#ifdef TEST
#import "Name_Test-Swift.h"
#elif LOCAL
#import "Name_Local-Swift.h"
#else
#import "Name-Swift.h"
#endif
I have imported several Swift classes that I use frequently and everything works fine.
Now....
I added a new Swift class. This new class is subclass of NSObject
class NewClass: UIView { }
But using the new class in a Objective-C class, Xcode can't find this new class, with these errors:
# import "Name-Swift.h" is not recognized.
NewClass *item = [NewClass alloc]; - Unknown type name 'NewClass'
I checked the following:
- The new class is added to all Targets and is verified in the Build-Phases->Compile-Sources section
My other Swift classes don't have public or #objc identifiers, and everything works OK..... So I still I tried using them in the new class (#objc and public in the class definition), with no success
With only adding NewClass *item = [NewClass alloc]; in any Objective-C class makes Xcode to stop recognizing "Name-Swift.h"
Any idea what is missing?
After some testing, I found that I need to import the Name-Swift.h file in the .h file where I want to declare my object.
My project defines the #import Name-Swift.h in the Name-Prefix.pch
#ifdef TEST
#import "Name_Test-Swift.h"
#elif LOCAL
#import "Name_Local-Swift.h"
#else
#import "Name-Swift.h"
#endif
The #import declaration in the .pch file allows the Swift class to be accesible anywhere from the .m file of my Objective-C class, but not from the .h
I am not sure if that is the expected behavior... I will do a deep dive to the Documentation.

No Setter method for assignment to property - cocoa application

I'm fairly new to objective-c and have just encountered an error i've not seen before.
I'm trying to set a Text Field cell as 'selectable', but i get the error "No Setter method 'setIsSelectable' for assignment to property."
Here are the .h and .m files.
Thanks.
DataPanel.h
#import <Cocoa/Cocoa.h>
#interface DataPanel : NSPanel
#property (weak) IBOutlet NSTextFieldCell *textField;
#end
DataPanel.m
#import "DataPanel.h"
#implementation DataPanel
#synthesize textField = _textField;
- (void) awakeFromNib{
_textField.stringValue = #"1.1 Performance standards The overall objective of the performance standards in Section 1.1 is to provide acoustic conditions in schools that (a) facilitate clear communication of speech between teacher and student, and between students, and (b) do not interfere with study activities.";
_textField.isSelectable = YES;
}
#end
In Objective-C, BOOL properties which start with 'is' are usually the getter of the property only, and not the property itself.
Its a convention.
Just for general knowledge, you can do so yourself by declaring properties in the following manner:
#property (nonatomic, getter=isAvaiable) BOOL available;
So trying to set the above, while using isAvailable will not work, since it is the getter method, and you can't set a getter.
As for your question,
Try changing your code from _textField.isSelectable = YES; to either of the below, and it should work.
_textField.selectable = YES;
[_textField setSelectable:YES];
Good luck mate.

Mark property as deprecated in Objective C

How can I mark a #property in Objective C as deprecated?
Unless you really want to deprecate based on iOS version, which I suspect you don't want to do, you can use DEPRECATED_ATTRIBUTE
#property (strong) NSObject *object DEPRECATED_ATTRIBUTE;
from NSObjCRuntime.h
#define NS_AVAILABLE(_mac, _ios)
#define NS_AVAILABLE_MAC(_mac)
#define NS_AVAILABLE_IOS(_ios)
#define NS_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep)
#define NS_DEPRECATED_MAC(_macIntro, _macDep)
#define NS_DEPRECATED_IOS(_iosIntro, _iosDep)
you can use these macros
this is one example in UITableViewCell.h
#property(nonatomic,copy) NSString *text NS_DEPRECATED_IOS(2_0, 3_0); // default is nil
You can also use DEPRECATED_MSG_ATTRIBUTE("Use anotherProperty instead.") and provide a meaningful message hinting the user what to use in place of the deprecated property.
Xcode will show a warning when the property is used.
example:
#property (nonatomic) NSString *someProperty DEPRECATED_MSG_ATTRIBUTE("Use anotherProperty instead.");
you can type macro like this below one in .pch to be gloabl for all the app
#define DEPRECATED_ATTRIBUTE __attribute__((deprecated))
in mark the method as following example
-(void) exmapleMethodName DEPRECATED_ATTRIBUTE{
// code
}

Declaring extern NSString causes linker error

This is ridiculous, im trying to create a sound bool to turn of in app sounds. I keep getting
Undefined symbols for architecture i386:
"_kPlaySoundPrefsKey", referenced from:
-[AppDelegate application:didFinishLaunchingWithOptions:] in AppDelegate.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I have checked that all my files are linked in build phases, I have deleted the appdelegate .m where im getting the error before I even get to call the bool in any of my view controllers, and re imported it in build phases. Checked I have relevant framweworks in place. I have even checked a previous app I made with same code and the code it appears to be exactly the same with no error (built with previous version of xcode). Taking it right back to basics I get the error as soon as I add the following code to my App Delegate,
.h
#import <UIKit/UIKit.h>
extern NSString *kPlaySoundPrefsKey;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
.m
#import "AppDelegate.h"
#import <AudioToolbox/AudioToolbox.h>
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
NSDictionary *defaultDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:kPlaySoundPrefsKey];
return YES;
}
If I change extern NSString *kPlaySoundPrefsKey; to NSString *kPlaySoundPrefsKey; it builds then crashes...Im out of ideas now
When you declaring something as extern you are telling the compiler the type AND that you will define it somewhere else. In your case you never define your variable.
So in your .h you would have:
extern NSString* kPlaySoundPrefsKey;
But in some .m you must also have
NSString* kPlaySoundPrefsKey = #"play_sounds"; // or some value
Since in your case these are constants you can also specify:
extern NSString* const kPlaySoundPrefsKey;
and
NSString* const kPlaySoundPrefsKey = #"play_sounds";
The addition of the const qualifier will cause a compiler error if someone ever writes something like
kPlaySoundPrefsKey = #"some_other_value";
I am also got the same error even if I am properly declared and define the extern const string ,
The problem is, my constant file not in the compile source list .
Make sure that your .m file appears in the "Compile Sources" Build Phase for your build target. Sometimes, adding files to a project in Xcode doesn't add all implementation files to the appropriate targets.
Hope this will helpful for some people.
Refe: linker-error-undefined-symbols-symbols-not-found
First, ensure it is defined:
// AppDelegate.h
extern NSString* const kPlaySoundPrefsKey; // << declaration
// AppDelegate.m
NSString * const kPlaySoundPrefsKey = #"kPlaySoundPrefsKey"; // << definition
see also:
"extern const" vs "extern" only
3 questions about extern used in an Objective-C project
Linker error using extern "C" in Objective-C code
Thanks for your help guys
I added
NSString *kPlaySoundPrefsKey = #"playSoundKey";
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultDict];
to app delegate. That fixed it