How to pass parameter in swift controller to objective c model? - objective-c

I couldn't figure out on how to pass variables with type String in swift controller files and pass it to object written in objective-c. However, if I pass a string directly as a parameter it works just fine. Thank you for your help.
This is the objective-c class below
#import "Message.h"
#implementation Message
- (instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self)
{
self.userID = dictionary[#"user_id"];
self.username = dictionary[#"username"];
self.avatarURL = dictionary[#"avatar_url"];
self.text = dictionary[#"message"];
}
return self;
}
- (instancetype)initWithTestName:(NSString *)name withTestMessage:(NSString *)message withUserId:(NSString *)userId withAvatarUrl:(NSString *)url
{
self = [super init];
if (self)
{
self.userID = userId;
self.username = name;
self.avatarURL = url;
self.text = message;
}
return self;
}
#end
and this is the swift controller file
import UIKit
class ChatViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private var messages = [Message]()
override func viewDidLoad() {
super.viewDidLoad()
// I can pass the string successfully to the messages this way
messages.append(Message(testName: "Test", withTestMessage: "Hello", withUserId: "1", withAvatarUrl: "http://www.example.com"))
// After successfully making Api Request, I wasn't able to pass a variable as parameter
if let data = dic as? [String:Any]{
let userId = data["user_id"] as? String
let url = data["avatar_url"] as? String
let name = data["name"] as? String
let message = data["message"] as? String
self.messages.append(Message(testName: name, withTestMessage: message, withUserId: userId, withAvatarUrl: url))
}
}
}

Related

How set title of a WKInterfaceButton?

I'm trying to change the text of a button once it is pressed however it doesn't work. Am i missing something?
i've been trying to figure my problem for hours.
any help would be appreciated.
h. file
#import <WatchKit/WatchKit.h>
#import <Foundation/Foundation.h>
#interface InterfaceController : WKInterfaceController
{
IBOutlet WKInterfaceButton*playpausebtn;
}
-(IBAction)play;
#end
m. file
#import "InterfaceController.h"
#import <WatchConnectivity/WatchConnectivity.h>
#interface InterfaceController() <WCSessionDelegate>
#end
#implementation InterfaceController
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
}
- (void)willActivate {
[super willActivate];
if ([WCSession isSupported]) {
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
}
- (void)didDeactivate {
// This method is called when watch view controller is no longer visible
[super didDeactivate];
}
-(IBAction)play{
[playpausebtn setTitle:#"sleep"];
}
It is working fine in Swift-3 Xcode-8.1 .
// InterfaceController.swift
// WatchKit Extension
import WatchKit
import Foundation
import WatchConnectivity
class InterfaceController: WKInterfaceController,WCSessionDelegate {
#IBOutlet var textLabel: WKInterfaceLabel!
var session:WCSession?
override func awake(withContext context: Any?) {
super.awake(withContext: context)
// Configure interface objects here.
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
checkSupportOfSession()
changeAttributeOfText()
}
#IBOutlet var buttonOutlet: WKInterfaceButton!
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
func checkSupportOfSession() {
if( WCSession.isSupported() ) {
self.session = WCSession.default()
self.session?.delegate = self
self.session?.activate()
}
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
print("session")
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
let message:String = message["textIndex"] as! String
textLabel.setText(message)
print(message)
}
func changeAttributeOfText() {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .left
let font = UIFont.boldSystemFont(ofSize: 12)
let attributes:Dictionary = [NSParagraphStyleAttributeName:paragraphStyle , NSFontAttributeName:font ]
let attributeString:NSAttributedString = NSAttributedString(string: "HELLO", attributes: attributes)
textLabel.setAttributedText(attributeString)
}
//Change the ButtonTitle after click
#IBAction func buttonClicked() {
buttonOutlet.setTitle("textNew")
}}
Demo App

Singleton in swift to Objective-C giving error property not found of type XYZ *

I have a function in swift as follows
public class XYZ:NSObject {
public static func getInstance() -> GlobalEventBus {
return globalEventBusInstance
}
public static var xyzInstance:XYZ = XYZ()
var initialized:Bool?
public func dispatchEvent(customEvent:CustomEvent) { }
override init() {
initialized = true
}
}
I used the getInstance function in objective C implementation as follows
#implementation SomeFile
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
/* log a message */
- (void)sendEvent:(CDVInvokedUrlCommand*)command
{
id message = [command argumentAtIndex:0];
XYZ *xyzInstance = [XYZ getInstance];
CustomEvent *customEvent = [CustomEvent alloc];
xyzInstance.dispatchEvent(customEvent)
//customEvent.eventType =
}
#end
The problem i am seeing is that I see an error
"Property dispatchEvent not found on object of type XYZ *"
Does it have anything to do with the fact that the instance variable being returned is a static variable? What am I doing wrong? Please help
Thank you
Nikhil
In your Objective-C code, you have a line that says:
xyzInstance.dispatchEvent(customEvent)
That's Swift. You want:
[xyzInstance dispatchEvent:customEvent];

Extract notification userinfo in a mixed language project

I am working on a mixed language project, combining both Objective C and Swift in XCode 6.
In this project, the Singleton (Objective C) class posts a notification which is then received by ViewController (Swift).
Singleton.h
#import <Foundation/Foundation.h>
NSString *const notificationString = #"notificationString";
#interface Singleton : NSObject
+ (id)sharedSingleton;
- (void)post;
#end
Singleton.m
#import "Singleton.h"
static Singleton *shared = nil;
#implementation Singleton
- (id)init {
self = [super init];
if (self) {
}
return self;
}
#pragma mark - Interface
+ (Singleton *)sharedSingleton {
static dispatch_once_t pred;
dispatch_once(&pred, ^{
shared = [[Singleton alloc] init];
});
return shared;
}
- (void)post {
char bytes[5] = {5, 7, 9, 1, 3};
NSDictionary *objects = #{#"device":[NSData dataWithBytes:bytes length:5], #"step1":[NSNumber numberWithInt:4], #"step2":[NSNumber numberWithInt:7]};
[[NSNotificationCenter defaultCenter] postNotificationName:notificationString
object:self
userInfo:objects];
}
#end
Of course, in this mixed-language project, bridging header must be setup correctly (just by adding #import "Singleton.h" in it)
ViewController.swift
import UIKit
class ViewController: UIViewController {
let singleton = Singleton.sharedSingleton() as Singleton
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "action:", name: notificationString, object: nil)
singleton.post()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Notification
func action(notification: NSNotification) {
let userInfo = notification.userInfo as Dictionary<String, String> // things go wrong here?!
let hash = userInfo["device"]
let completed = userInfo["step1"]
let total = userInfo["step2"]
}
}
This makes no compilation error. However, at run time, XCode reports:
fatal error: dictionary cannot be bridged from Objective-C
notification.userInfo contains an NSDictionary built by NSSTring: NSData, NSSTring: NSNumber, NSSTring: NSNumber while this command let userInfo = notification.userInfo as Dictionary<String, String> is trying to convert to Dictionary<String, String>
Does this cause the fatal error?
In ViewController.swift, what should I do to "read" NSDictionary passed in notification.userInfo, sent from Singleton.m?
Thanks in advance
try doing this
let userInfo = notification.userInfo as Dictionary<String, AnyObject>
as you indicated, the userInfo dictionary contains NSData, NSNUmber for values.

Are local static variables released on dealloc in Objective-C / ARC?

I have a factory which handles singletons as follows
#implementation MyFactory
- (AudioEngine *)theAudioEngine
{
static AudioEngine *ae = nil;
if (ae == nil) {
ae = [[AudioEngine] alloc] init];
}
return ae;
}
#end
Are such static local variables released when the MyFactory instance is dealloc'ed?
No they are not released. You could however move the variable to the heap and have a class method to release it, which is itself called from some app-level closedown method:
static AudioEngine *_ae = nil;
#implementation MyFactory
- (AudioEngine *)theAudioEngine
{
if (_ae == nil) {
_ae = [[AudioEngine] alloc] init];
}
return _ae;
}
+ (void)cleanup
{
if (_ae != nil)
{
// No need to release when in ARC mode (thanks to #AndrewMadsen)
//[_ae release];
_ae = nil;
}
}
#end
As stated by #trojanfoe the answer is no, presumably because the compiler allocates a permanent space for the static var and being also a local var, only the method itself would ever have access to it and thus the ability to dealloc it (via = nil).
Another strategy which works presuming your factory is an instance object and not a static class:
#implementation MyFactory
{
AudioEngine *_audioEngine;
}
- (AudioEngine *)audioEngineSingleton
{
if (_audioEngine == nil) {
_audioEngine = [[AudioEngine alloc] init];
}
return _audioEngine;
}
#end
When your MyFactory instance dealloc's so will the ivars.

How to define an initializer to fill BaseClass properties using BaseClass objects?

I have two classes:
BaseClass : NSObject
AdvanceClass : BaseClass
And in AdvanceClass i have an initializer:
-(id)initWithBaseObject:(BaseClass *)bObj
{
if(self = [super init]) {
self = (AdvanceClass*)bObj;
}
return self;
}
And then when i get TRUE when i'm calling:
[myObject isKindOfClass:[BaseClass class]]
Why? I'm casting bObj to AdvanceClass object.
What i want to do here is assign all of the properties from BaseClass with properties from bObj object. How can i do that?
-(id)initWithBaseObject:(BaseClass *)bObj
{
if(self = [super init]) {
self = (AdvanceClass*)bObj; // this line of code discards the self = [super init]; and makes self a reference to a casted BaseClass object
self.property1 = bObj.property1; // this is what you need to do for each property and remove the line with the cast
}
return self;
}
I've just realize that the best way is write a public method in BaseClass and call it from initializer. In that case you can only write this once, and it is simply to edit.
-(id)initWithBaseObject:(BaseClass *)bObj
{
if(self = [super init]) {
[self setBaseProperties:bObj];
}
return self;
}
And in BaseClass.m
-(void)setBaseProperties:(BaseClass*)bObj
{
_prop1 = bObj.prop1;
_prop2 = bObj.prop2;
.
.
.
}
This is obvious solution, silly me.