Here is an UIView extension written in ObjectiveC to easily create view for using Auto-layout:
+(id)autolayoutView
{
UIView *view = [self new];
view.translatesAutoresizingMaskIntoConstraints = NO;
return view;
}
it invokes [self new] so any subclass of UIView can use this method. How can I achieve this in Swift?
OK, this appears to be the solution. The type must have a required initializer with the correct parameter list (in this case no parameters).
class SubView: UIView {
override required init() {
super.init()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
class func autolayoutView() -> UIView {
var view = self()
view.setTranslatesAutoresizingMaskIntoConstraints(false)
return view
}
}
Though both Carrl and Gregory Higley are right with there solutions, including thr remark about the fact that self() needs to use a required init i wanted to post a more general example:
class Human {
var gender = String()
required init() {
self.gender = "any"
}
class func newHuman() -> Human {
return self()
}
}
class Man : Human {
required init() {
super.init()
self.gender = "male"
}
}
var someMan = Man.newHuman()
println(someMan.gender) // male
Inspired by Gregory Higley, i think the solution is here:
extension UIView{
class func autolayoutView() -> UIView {
var view = self()
view.setTranslatesAutoresizingMaskIntoConstraints(false)
return view
}
}
Update for Swift2.1:
extension UIView{
class func autolayoutView() -> UIView {
let view = self.init()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}
}
Related
I have a UIBarButtonItem subclass, "NavBarButtonItem", defined in Swift 3.0 but am not sure if I've set up the convenience initializer properly. This initializer seems works fine in other Swift classes:
let nextBarButtonItem = NavBarButtonItem.init(self, "Next", #selector(pressedNextButton))
However, in Obj-C, Xcode presents me with the following (it's missing argument labels):
self.nextButton = [NavBarButtonItem alloc] init:<#(id<NavBarButtonDelegate> _Nonnull)#> :<#(NSString * _Nonnull)#> :<#(SEL _Nonnull)#>
and I've completed it with:
self.nextButton = [[NavBarButtonItem alloc] init:rvc :2 :#"Next" :#selector(doneButtonTapped:)];
I've not set up initializers in Swift before so suspect that there might be something wrong but the app compiles. Here's the Swift subclass:
MyViewController.swift
// this file contains other classes that precede subclass NavBarButtonItem
..
#objc protocol NavBarButtonDelegate {
func pressedNextButton()
}
#objc class NavBarButtonItem: UIBarButtonItem
{
private var delegate: NavBarButtonDelegate?
init(_ delegate: NavBarButtonDelegate){
self.delegate = delegate
super.init()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
convenience init(_ delegate: NavBarButtonDelegate, _ title: String, _ selector: Selector)
{
self.init(delegate, wtfProperty)
self.title = title
self.action = selector
}
}
What will be the syntax of the following Objective-C method in Swift?
-(id)init
{
Viewcontroller static *vc=nil;
if(!vc)
{
vc=[super init];
return vc;
}
else return vc;
}
Below is the syntax in Swift 3
override init() {
var vc: Viewcontroller? = nil
if vc == nil {
vc = super.init()
return vc!
}
else {
return vc!
}
}
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
I have a code below trying to use swizzling method to UIApplication methods. But the methods not getting called. Meanwhile, I'm trying to add this code into a framework or a private pod.
extension UIApplication {
public override class func initialize() {
struct Static {
static var token: dispatch_once_t = 0
}
struct SwizzlingSelector {
let original:Selector
let swizzled:Selector
}
// make sure this isn't a subclass
if self !== UIApplication.self {
return
}
dispatch_once(&Static.token) {
let selectors = [
SwizzlingSelector(
original: Selector("application:didFinishLaunchingWithOptions:"),
swizzled: Selector("custome_application:didFinishLaunchingWithOptions:")
),
SwizzlingSelector(
original: Selector("applicationDidEnterBackground:"),
swizzled: Selector("custom_applicationDidEnterBackground:")
)
]
for selector in selectors {
let originalMethod = class_getInstanceMethod(self, selector.original)
let swizzledMethod = class_getInstanceMethod(self, selector.swizzled)
let didAddMethod = class_addMethod(self, selector.original, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(self, selector.swizzled, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
}
}
// MARK: - Method Swizzling
public func custome_application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
print("is here")
return true
}
func custom_applicationDidEnterBackground(application: UIApplication) {
print("is herer")
}
}
I think you should implement this swizzling method in your AppDelegate but not as extension of UIApplication. Cause you swizzle your AppDelegate's methods but not UIApplication's methods.
extension YourAppDelegate {
public override class func initialize() {
struct Static {
static var token: dispatch_once_t = 0
}
struct SwizzlingSelector {
let original:Selector
let swizzled:Selector
}
// make sure this isn't a subclass
if self !== YourAppDelegate.self {
return
}
dispatch_once(&Static.token) {
let selectors = [
SwizzlingSelector(
original: Selector("application:didFinishLaunchingWithOptions:"),
swizzled: Selector("custome_application:didFinishLaunchingWithOptions:")
),
SwizzlingSelector(
original: Selector("applicationDidEnterBackground:"),
swizzled: Selector("custom_applicationDidEnterBackground:")
)
]
for selector in selectors {
let originalMethod = class_getInstanceMethod(self, selector.original)
let swizzledMethod = class_getInstanceMethod(self, selector.swizzled)
let didAddMethod = class_addMethod(self, selector.original, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(self, selector.swizzled, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
}
}
// MARK: - Method Swizzling
public func custome_application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
print("is here")
return true
}
func custom_applicationDidEnterBackground(application: UIApplication) {
print("is herer")
}
}
I have two delegates like this:
protocol MyFirstDelegate {
func change(value: int)
}
protocol MySecondDelegate {
weak var delegate: MyFirstDelegate?
}
Those protocols are implemented in two customized UIViewControllers:
class MyFirstViewController: UIViewController, MyFirstDelegate {
...
}
class MySecondViewController: UIViewController, MySecondDelegate {
...
}
The first UI view controller will push second UI view controller by using a segue.
In my first UI view controller class I have the following codes to prepare segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if let vc = (segue.destinationViewController) as? MySecondViewController {
vc.delegate = self
}
}
The above codes compile without any problem. However, I think that the first UI controller has knowledge about the next view controller class. I prefer to pass delegate like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if var vc = (segue.destinationViewController) as? MySecondDelegate {
vc.delegate = self
}
}
I got compiling error:
Cannot assign to property: "vc" is immutable.
It seems that as to a concrete UI view controller is OK, but not to a protocol. Any explanation and solution to this?
By the way, in Objective-C, this can be done like this:
id<NSObject, MySecondDelegate> vc = segue.destinationViewController;
vc.delegate = self;
I could not find a way in swift to define a variable like
let vc: AnyObject<type>? // like id<type>
UPDATES
As #David_Berry solution, it works if I mark protocol as class. The above codes are actually simplified ones. I am in the middle of converting my ObjC codes to Swift. Therefore, I have to mark protocols as objc:
#objc protocol MyFirstDelegate : class {
func change(value: int)
}
#objc protocol MySecondDelegate {
weak var delegate: MyFirstDelegate?
}
with #objc, I still get the same compiling error.
Well, I finally managed to get your example to compile, you have a LOT of inconsistencies. The key to your actual problem, I think, is requiring that the protocols be class protocols:
protocol XXX : class { }
Says that only types that are classes can be declared to implement XXX.
But, I'm really not sure that's your problem, there were so many other changes required (you spelled MySecondDelegate at least two ways, MySecondViewController at least two ways, etc.
The compiling example is:
// This protocol has to be class so that delegate can be weak
protocol MyFirstDelegate : class {
func change(value: Int)
}
protocol MySecondDelegate {
weak var delegate: MyFirstDelegate? { get set }
}
class MyFirstViewController: UIViewController, MyFirstDelegate {
func change(value: Int) {
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if var vc = (segue.destinationViewController) as? MySecondDelegate {
vc.delegate = self
}
}
}
class MySecondViewController: UIViewController, MySecondDelegate {
weak var delegate : MyFirstDelegate?
}
As for your question, there is no swift synonym to the objective-C syntax id<Protocol> or Class<Protocol> There are multiple duplicates to that issue that offer alternatives.