Making some code only run once - objective-c

I have some code that I would like to run only once in my MainViewController. It should run every time the user starts the app, but only after the MainViewController has loaded.
I don't want to run it in -(void)applicationDidFinishLaunching:(UIApplication *)application.
Here's the idea I had:
MainViewController.h
#interface IpadMainViewController : UIViewController <UISplitViewControllerDelegate> {
BOOL hasRun;
}
#property (nonatomic, assign) BOOL hasRun;
MainViewController.m
#synthesize hasRun;
-(void)viewDidLoad {
[super viewDidLoad];
if (hasRun == 0) {
// Do some stuff
hasRun = 1;
}
}
Any ideas?

Swift 1,2:
static var token: dispatch_once_t = 0
dispatch_once(&token) {
NSLog("Do it once")
}
Objective-C
static dispatch_once_t once;
dispatch_once(&once, ^ {
NSLog(#"Do it once");
});
Swift 3,4:
dispatch_once is no longer available in Swift. In Swift, you can use
lazily initialized globals or static properties and get the same
thread-safety and called-once guarantees as dispatch_once provided
Apple doc
let myGlobal = { … global contains initialization in a call to a closure … }()
_ = myGlobal // using myGlobal will invoke
// the initialization code only the first time it is used.

I don't see any problem with that code. I like using a BOOL (as you did) and then assigning either YES/NO or TRUE/FALSE just so that the code reads more nicely. I would assign TRUE to firstRun in didFinishLaunching, and set it FALSE after the code executes. In my code these type of conditionals usually look like this:
#synthesize firstRun;
-(void)viewDidLoad {
[super viewDidLoad];
if (firstRun) {
// code to run only once goes here
firstRun = FALSE;
}
}

Possible variation (Swift 5):
// Whether this is the first code run since app (re)started
var firstRun: Bool = true
public final class Foo {
public init() {
if firstRun {
// Code that has to be run only once goes
// HERE
firstRun = false
}
}
}

Since there is no dispatch_once_t ins swift 3 and above, we can use lazy initialized global variables.
Make a lazy global variable
lazy var doOnlyOnce: () -> Void = {
.. add code to run only once here ..
return {}
}()
To run the code:
_ = doOnlyOnce

With Swift2.0, Xcode 7.0
var token: dispatch_once_t = 0
override func viewDidLoad() {
super. viewDidLoad()
dispatch_once(&token) {
println("This is printed only on the first call to test()")
}
println("This is printed for each call to test()")
}

for Swift2.2,Xcode 7.3:
static var token: dispatch_once_t = 0
dispatch_once(&YourClassName.token) {
NSLog("Do it once")
}
Watch out "YourClassName.token"

Related

Invoke Swift closure in Objective-C

I want to invoke a Swift closure in Objective-C.
There is an error like this even though I declared the function:
No visible #interface for “User” declares the selector “isReady”
Swift:
#objcMember
class User:NSObject {
func isReady(isTrue: Bool) -> Bool {
return true
}
}
Objective-C:
User *user = [[User alloc] init];
[_user isReady]. <- error
Add to the function #objc modifier:
#objcMember
class User:NSObject {
#objc public func isReady(isTrue: Bool) -> Bool {
return true
}
}
And add public modifier to the function to allow access from other modules (swift code builds as module and ObjC code should export it and access via open interfaces).

swift 3 _ObjectiveCBridgeable conformance

I am trying to make a swift 3 struct conform to _ObjectiveCBridgeable but I am not sure what else I need to satisfy the protocol. Below is my struct and the _ObjectiveCBridgeable conformance. I am missing something but I am not sure what it is.
struct Box {
let contents: Any
}
extension Box: _ObjectiveCBridgeable {
typealias _ObjectiveCType = thing;
init(fromObjectiveC source: _ObjectiveCType) {
contents = source.contents
}
static func _isBridgedToObjectiveC() -> Bool {
return true
}
static func _getObjectiveCType() -> Any.Type {
return _ObjectiveCType.self
}
func _bridgeToObjectiveC() -> Box._ObjectiveCType {
return thing(contents: self.contents)
}
static func _forceBridgeFromObjectiveC(_ source: Box._ObjectiveCType, result: inout Box?) {
result = Box(contents: source.contents)
}
static func _conditionallyBridgeFromObjectiveC(_ source: Box._ObjectiveCType, result: inout Box?) -> Bool {
_forceBridgeFromObjectiveC(source, result: &result)
return true
}
}
// Objc
#interface thing : NSObject
#property (readonly) id contents;
-(instancetype)initWithContents:(id)contents;
#end
#implementation thing
- (instancetype)initWithContents:(id)contents {
if ((self = [super init])) {
_contents = contents;
}
return self;
}
#end
As the underscore tells you, _ObjectiveCBridgeable is private. Its purpose is "to accommodate the specific needs of bridging Objective-C object types to Swift value types". You cannot adopt it for your own types; it works by means of "compiler magic under the hood".
There is a proposal on the table to provide a public version, but it has not yet been implemented.

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];

init an NSNumber from enum element in mixed-language project

I have a mixed-language project, Objective C and Swift, in XCode 6.
Singleton.h
#import <Foundation/Foundation.h>
enum {
enum_A = 0,
enum_B,
enum_C,
enum_D,
enum_E,
enum_F,
enum_G,
} enums;
#interface Singleton : NSObject
+ (id)sharedSingleton;
#end
Singleton.m
// Nothing's special in this file
#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;
}
#end
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.
let n = NSNumber(char: enum_E) // ERROR HERE!!!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
(Of course I had to setup bridging header file, having #import "Singleton.h" added).
The ERROR is:
Cannot invoke 'init' with an argument list of type '(char: Int)'
It's strange that Swift can still recognize enum_E (I see it colorized in blue) but still pops up this error.
I tried (char)enum_E but still no luck.
Do you have any ideas?
Thanks,
Okay, apparently there actually is a difference between enums created in Objective-C and Swift. I assumed there was no difference, thus I only tested my approach in a Swift Playground.
enum created in Swift
// UInt32 used to have the same underlying type in both examples
enum TestEnum : UInt32 {
case A, B, C
}
var x = NSNumber(unsignedInt: TestEnum.C.rawValue)
// x == 2
To get the raw value from an enum value in Swift, you have to explicitly transform the enum value into the raw value. This can be done by adding .rawValue to your enum value.
enum created in Objective-C
Objective-C
enum TestEnum {
A = 0,
B = 1,
C = 2
};
Swift
let x : TestEnum = C
var number = NSNumber(unsignedInt: C.value) // alternative: x.value
println("the number is \(number)")
// Outputs: the number is 2
The difference to the Swift enums seems to be that you have to use .value instead of .rawValue and you can not prefix them with the type. The raw type in this case is UInt32.
Tested in Xcode 6.1.1, iOS SDK 8.1, iOS Simulator 8.1

acceptsFirstResponder in NSViewController and xcode 6 - Swift

Could somebody explain to me how I can set acceptsFirstResponder on a NSViewController in Swift and xcode 6?
The program doesn't allow any overriding of the function and says it doesn't exist in the superclass but I can also not set it as a variable like:
self.acceptsFirstResponder = true
Anybody know?
I had a similar issue but with a NSView Class. I was able to make this work with the following. I had to put it in the class outside any functions.
import Cocoa
class MyView: NSView, NSDraggingDestination {
//MARK: Variables
override var acceptsFirstResponder: Bool { return true }
override var opaque: Bool { return true }
var bgColor : NSColor = .yellowColor()
var lastString : String = ""
var attributes : NSMutableDictionary = [:]
var highlightNeeded = false