2016-09-05 10:26:53 wahaha13168 阅读数 2165
  • c++基础第二季

    从简单语名到复合语句 单次循环句话 if语句的用法 switch的用法 多次循环语句 for的用法 while的用法 有问题咨询老师微信,微信号:mikeshizhanbiao do while 用法。 struct的用法及注意事项 union的用法及注意事项 文件的读写操作及删除 指针类型的用法及注意事项 引用类型 一维数组,二维数组的用法,杨辉三角的打印。 1.函数的声明定义 2.内联函数 3.函数的递归调用 5.函数模板函数指针

    11345 人正在学习 去看看 师占标

oc中调用swift中的struct 

在oc中是不能调用struct里面的内容的,你想在类似class前面加个@objc的方法加在struct前面,你是发现是不行的,那但是我们又想在oc中调用struct的属性,那怎么办呢?我们只能够再建一个类

在类里写个方法来返回struct中的值


2019-05-07 11:35:12 Bolted_snail 阅读数 275
  • c++基础第二季

    从简单语名到复合语句 单次循环句话 if语句的用法 switch的用法 多次循环语句 for的用法 while的用法 有问题咨询老师微信,微信号:mikeshizhanbiao do while 用法。 struct的用法及注意事项 union的用法及注意事项 文件的读写操作及删除 指针类型的用法及注意事项 引用类型 一维数组,二维数组的用法,杨辉三角的打印。 1.函数的声明定义 2.内联函数 3.函数的递归调用 5.函数模板函数指针

    11345 人正在学习 去看看 师占标
  • 最近在一个混编项目中,一个OC类需要去访问一个Swift类,访问其他Swift类都可以,但就没法访问报以下错误:
    报错
  • 点进去看发现该类型是个结构体,如下所示:
    在这里插入图片描述在这里插入图片描述
  • 解决方案:因为Swift的结构体除了不能继承外可以有自己的成员变量和方法,就是一个不能继承的类.所以我将struct改成了class,结果还是不行.后来就像因为Swift中的类可以没有父类,而OC的中有基类的,所有类都最终继承至NSObject,所以就将该CTPCarVideoUploadInfoModel也继承NSObject,果然改完后再OC中就可以访问该类型了.改完后如下:
     class CTPCarVideoUploadInfoModel:NSObject{
     }
    
2016-09-13 01:14:27 asuno_1 阅读数 1893
  • c++基础第二季

    从简单语名到复合语句 单次循环句话 if语句的用法 switch的用法 多次循环语句 for的用法 while的用法 有问题咨询老师微信,微信号:mikeshizhanbiao do while 用法。 struct的用法及注意事项 union的用法及注意事项 文件的读写操作及删除 指针类型的用法及注意事项 引用类型 一维数组,二维数组的用法,杨辉三角的打印。 1.函数的声明定义 2.内联函数 3.函数的递归调用 5.函数模板函数指针

    11345 人正在学习 去看看 师占标

静态全局变量分swift和oc版

swift版相对比较简单

struct Example {

    static var example:String = ""

}

oc

先写设置静态变量的方法

#import <Foundation/Foundation.h>


@interface staticPool : NSObject

//静态变量的set get 方法

+(void)setName:(NSString *)Name;

+(NSString *)getName;


+(void)setAge:(NSInteger)Age;

+(NSInteger)getAge;




@end


#import "staticPool.h"

//创建静态全局变量

static NSString *name = nil;

static  NSInteger age = 0;




@implementation staticPool


+(void)setName:(NSString *)Name

{

    name = Name;

}


+(NSString *)getName

{

    return name;

}


+(void)setAge:(NSInteger)Age

{

    age = Age;

}


+(NSInteger)getAge

{

    return  age;

}




@end



然后调用设置

#import "ViewController.h"

#import "PageBViewController.h"

#import "staticPool.h"


@interface ViewController ()


@end


@implementation ViewController


- (void)viewDidLoad {

    [super viewDidLoad];

    [staticPool setAge:18];

    [staticPool setName:@"Clement"];

    

    UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(50, 100, 200, 50)];

    [btn setTitle:@"跳转到获取页面" forState:UIControlStateNormal];

    [btn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];

    [btn addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:btn];

}



-(void)click

{

    PageBViewController *page = [[PageBViewController alloc]init];

    [self presentViewController:page animated:YES completion:nil];


}


- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


@end



最后在另一个页面获取

#import "PageBViewController.h"

#import "staticPool.h"


@interface PageBViewController ()


@end


@implementation PageBViewController


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view.

    self.view.backgroundColor = [UIColor whiteColor];

    

    UILabel *name = [[UILabel alloc]initWithFrame:CGRectMake(50, 100, 200, 35)];

    UILabel *age = [[UILabel alloc]initWithFrame:CGRectMake(50, 200, 200, 35)];

    name.textColor = [UIColor orangeColor];

    age.textColor = [UIColor orangeColor];

    [self.view addSubview:name];

    [self.view addSubview:age];

   NSString *theName =  [staticPool getName];

   NSInteger theAge =  [staticPool getAge];

    name.text = theName;

    age.text = [NSString stringWithFormat:@"%d",theAge];

}


- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


/*

#pragma mark - Navigation


// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    // Get the new view controller using [segue destinationViewController].

    // Pass the selected object to the new view controller.

}

*/


@end


大工告成


2019-08-10 19:44:33 weixin_42433480 阅读数 15
  • c++基础第二季

    从简单语名到复合语句 单次循环句话 if语句的用法 switch的用法 多次循环语句 for的用法 while的用法 有问题咨询老师微信,微信号:mikeshizhanbiao do while 用法。 struct的用法及注意事项 union的用法及注意事项 文件的读写操作及删除 指针类型的用法及注意事项 引用类型 一维数组,二维数组的用法,杨辉三角的打印。 1.函数的声明定义 2.内联函数 3.函数的递归调用 5.函数模板函数指针

    11345 人正在学习 去看看 师占标

只能被class(类)继承的协议

  • 只能被class(类)继承的协议有三种:
  1. 继承自AnyObject
  2. 继承自class
  3. 被@objc修饰的类
protocol Runnable1: AnyObject { }
protocol Runnable2: class { }
@objc protocol Runnable3 { }

struct Animal: Runnable1 { } //error: Non-class type 'Animal' cannot conform to class protocol 'Runnable1'
struct Animal2: Runnable2 { } //error: Non-class type 'Animal' cannot conform to class protocol 'Runnable1'
struct Animal3: Runnable3 { } //error: Non-class type 'Animal' cannot conform to class protocol 'Runnable1'

class Student: Runnable1 { }
class Student2: Runnable2 { }
class Student3: Runnable3 { }
  • 被@objc修饰的协议,还可以暴露给OC去遵守实现

可选协议

  • 可以通过@objc定义可选协议,这种协议只能被class(类)遵守
@objc protocol Runnable {
    func run1()
    //可选方法,可实现,可不实现
    @objc optional func run2()
    func run3()
}

class Dog: Runnable {
    func run3() { print("Dog run3") }
    func run1() { print("Dog run1") }
}

var d = Dog()
d.run1() //Dog run1
d.run3() //Dog run3

dynamic

  • 被@objc dynamic修饰的内容会具有动态性,比如调用方法会走runtime那一套
class Dog: NSObject {
    @objc dynamic func test1 () { }
    func test2() { }
}
var d = Dog()
d.test1()
d.test2()
  • test1会走runtime的objc_msgSend,底层汇编代码如下:

  • test2会走Swift的callq虚表那一套,底层汇编代码如下:


KVC\KVO

  • Swift支持KVC\KVO的条件
  1. 属性所在的类、监听器最终继承自NSObject,因为KVC\KVO走的是runtime那一套,所以要继承NSObject
  2. 用@objc dynamic修饰对应的属性
class Observer: NSObject {
    override func observeValue(forKeyPath keyPath: String?,
                               of object: Any?,
                               change: [NSKeyValueChangeKey : Any]?,
                               context: UnsafeMutableRawPointer?) {
        print("observeValue", change?[.newKey] as Any)
    }
}

class Person: NSObject {
    @objc dynamic var age: Int = 0
    var observer: Observer = Observer()
    override init() {
        super.init()
        self.addObserver(observer, forKeyPath: "age", options: .new, context: nil)
    }
    deinit {
        self.removeObserver(observer, forKeyPath: "age")
    }
}

var p = Person()
p.age = 20 //observeValue Optional(20)
p.setValue(25, forKey: "age") //observeValue Optional(25)
  • block方式的KVO
class Person: NSObject {
    @objc dynamic var age: Int = 10
    var observation: NSKeyValueObservation?
    override init() {
        super.init()
        observation = observe(\Person.age
            , options:.new, changeHandler: { (_, change) in
                print(change.newValue as Any)
        })
    }
}

var p = Person()
p.age = 20 //Optional(20)
p.setValue(25, forKey: "age") //Optional(25)

关联对象(Associated Object)

  • 在Swift中, class依然可以使用关联对象
  • 默认情况,extension不可以增加存储属性
  • 借助关联对象,可以实现类似extension为class增加存储属性的效果

示例1:

class Person { }
extension Person {
    private static var AGE_KEY: Void? //类属性相当于暴露在外面的全局变量,地址是固定的,这里可以看到AGE_KEY是Void?类型,占一个字节,也可以是bool类型,也占一个字节,这样做是为了节省内存
    var age: Int {
        get {
//           return (objc_getAssociatedObject(self, &Person.AGE_KEY) as? Int) ?? 0
           return objc_getAssociatedObject(self, &Person.AGE_KEY) as! Int
        }
        set {
            objc_setAssociatedObject(self, &Person.AGE_KEY, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN)
        }
    }
    
}

var p = Person()
p.age = 0
print(p.age) //0
p.age = 10
print(p.age) //10

示例2:

  • 关联对象怎么存储呢?最底层有一个哈希表(map),在表里会有一个存储对象信息的字典,关联对象时首先会传入一个对象,根据对象找到对应的value,value又是类似于字典一样的东西,再传入第二个参数一个固定的地址,根据地址就可以存储和获得所需要的属性值

资源名管理

  • 如果有太多需要调用名字为logo的图片或设置名字为添加的button,上面的写法一次次写未免太麻烦,所以要用到资源名管理,写法如下:
  1. 第一种写法

 注:case logo相当于case logo = "logo"

2)第二种写法

  • 更多优秀的思路参考:
  1. https://github.com/mac-cain13/R.swift
  2. https://github.com/SwiftGen/SwiftGen

多线程开发 - 异步

  • Asyncs.swift
  • DispatchWorkItem的notify是当异步线程执行完后通知主线程调用
import Foundation

public typealias Task = () -> Void

public struct Asyncs {
    
    public static func async(_ task: @escaping Task) {
        _async(task)
    }
    
    public static func async (_ task: @escaping Task,
                              _ mainTask: @escaping Task) {
        _async(task,mainTask)
    }
    
    private static func _async(_ task: @escaping Task,
                               _ mainTask: Task? = nil) {
        let item = DispatchWorkItem(block: task)
        DispatchQueue.global().async(execute: item)
        if let main = mainTask {
            //item.notify是当异步线程执行完后通知主线程调用
            item.notify(queue: DispatchQueue.main, execute: main)
        }
    }
}
  • ViewController.swift
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        Asyncs.async({ print(1)}) //1
        Asyncs.async({
            print(1, Thread.current) //1 <NSThread: 0x60000027f640>{number = 3, name = (null)}
        }) {
            print(2, Thread.current) //2 <NSThread: 0x604000261740>{number = 1, name = main}
        }
    }
}

多线程开发 - 延迟

  • Asyncs.swift
import Foundation

public typealias Task = () -> Void

public struct Asyncs {
    
    //返回值可以忽略,当你没用到返回值的时候,也不会报警告⚠️
    @discardableResult
    public static func delay (_ seconds: Double,
        _ block: @escaping Task) -> DispatchWorkItem {
        let item = DispatchWorkItem(block: block)
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds, execute: item)
        return item
    }
    
    @discardableResult
    public static func asyncDelay(_ seconds: Double,
                                  _ task: @escaping Task) -> DispatchWorkItem {
       return _asyncDelay(seconds, task)
    }
    
    @discardableResult
    public static func asyncDelay(_ seconds: Double,
                                  _ task: @escaping Task,
                                  _ mainTask: @escaping Task) -> DispatchWorkItem {
        return _asyncDelay(seconds, task, mainTask)
    }
    
    private static func _asyncDelay(_ seconds: Double,
                                    _ task: @escaping Task,
                                    _ mainTask: Task? = nil) -> DispatchWorkItem {
        let item = DispatchWorkItem(block: task)
        DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + seconds, execute: item)
        if let main = mainTask {
            item.notify(queue: DispatchQueue.main, execute: main)
        }
        return item;
    }
}
  • ViewController.swift
import UIKit

class ViewController: UIViewController {

    private var item: DispatchWorkItem?
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        item = Asyncs.delay(3) {
            print(1) //1
        }
        
        item = Asyncs.asyncDelay(3, {
            print(1, Thread.current) //1 <NSThread: 0x60400046e9c0>{number = 3, name = (null)}
        }, {
            print(2, Thread.current) //2 <NSThread: 0x60000007be80>{number = 1, name = main}

        })
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with: UIEvent?) {
        item?.cancel() //取消操作
    }
    
}

多线程开发 - once

dispatch_once在Swift中已被废弃,取而代之

  1. 可以用类型属性或者全局变量\常量

    static修饰的类型属性示例:

import UIKit

class ViewController: UIViewController {
    
    static var age: Int = getAge()
    static func getAge() -> Int {
        print("getAge")
        return 0
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print(ViewController.age)
        print(ViewController.age)
        print(ViewController.age)
    }
    
}
//输出结果
//getAge
//0
//0
//0

全局变量(默认lazy)示例:

import UIKit

//lazy
fileprivate var initTask: Void = {
    print("init-----")
}()
class ViewController: UIViewController {


    override func viewDidLoad() {

       super.viewDidLoad()

    }
    
    let _  = initTask
    let _ = initTask
    let _ = initTask
    
}

//输出结果
//init-----
//可以看到只调用了一次

2.   默认自带 lazy + dispatch_once 效果


多线程开发 - 加锁

  • gcd信号量

private static var lock = DispatchSemaphore(value: 1) 的(value: 1)代表在同一时刻,只有一条线程可访问,不能多条线程同时访问

  • Foundation

这是一般锁,不能针对递归调用,可能依然会遇到因递归造成的同时调用的问题而报错:

下面的是递归锁,能解决递归调用问题:

 

 

 

 

 

 

 

 

 

 

 

 

2016-01-29 11:48:53 showhilllee 阅读数 12670
  • c++基础第二季

    从简单语名到复合语句 单次循环句话 if语句的用法 switch的用法 多次循环语句 for的用法 while的用法 有问题咨询老师微信,微信号:mikeshizhanbiao do while 用法。 struct的用法及注意事项 union的用法及注意事项 文件的读写操作及删除 指针类型的用法及注意事项 引用类型 一维数组,二维数组的用法,杨辉三角的打印。 1.函数的声明定义 2.内联函数 3.函数的递归调用 5.函数模板函数指针

    11345 人正在学习 去看看 师占标

原创文章转载请注明出处。

背景


在上一篇文章swift与OC混编(创建混编工程)中简单讲述了怎么创建Swift和OC的混编工程。本篇讲一下Swift和OC的混编工程中的方法调用。

OC调用Swift


OC调用Swift方法比较简单。但是需要注意以下几点:

  • 1.需要在当前OC类里导入xxx-Swift.h头文件,其中xxx为项目名称(与你的项目配置相关,具体配置方式见上一篇文章)

  • 2.OC类里仅可以调用public的Swift方法和变量

  • 3.Swift类最好用@objc(xxx)进行描述

暂时想到这几点,如有疏漏请留言指出,不胜感激。

剩下的调用方式就和普通的OC之间调用方式类似了。

OC调用Swift实例方法


继续用上一篇文章的例子进行说明,例如在ViewController.m类里调用Swift的logMe实例方法,就可以这么写:

SwiftDemo* demo = [[SwiftDemo alloc] init];
[demo logMe];

OC调用Swift静态方法


首先先在SwiftDemo.swift文件中声明一个静态方法:

public static func swiftStaticFunc(log: NSString) {
    print(log);
}

然后回到ViewController.m类里调用该方法(记得编译一下才可以吆~)

桐乡的,调用方式和OC之间的调用类似:

[SwiftDemo swiftStaticFunc:@"oc call swift static func"];

Swift调用OC


前一篇文中也已经说过需要有一个桥接文件Swift才可以调用OC相关方法以及属性等,这里不再赘述,忘记了的可以再回去看一下。

Swift调用OC实例方法


其实前面文中已经举例说明了调用方法。这里再简单重复一下。

在SwiftDemo.swift类里调用ViewController.m类里的logYou方法,swift调用代码如下:

let vc = ViewController()
vc.logYou()

声明一个变量vc,也就是ViewController的实例对象。然后用vc对象调用实例方法logYou。

Swift调用OC多参方法


首先先在ViewController.h中声明一个OC的多参方法:

- (void) logMe:(NSString*)logMe logYou:(NSString*)logYou;

在.m文件中进行一下实现:

- (void)logMe:(NSString *)logMe logYou:(NSString *)logYou {
    NSLog(@"%@--%@", logMe, logYou);
}

在SwiftDemo.swift文件中调用方法如下:

vc.logMe("log me", logYou: "log you")

方法从第一个参数开始都要写在括号里。

Swift调用OC静态方法


首先先在ViewController.h中声明一个OC的静态方法:

+ (void) ocStaticFunc:(NSString*)log;

然后在.m文件中简单些一下实现:

+ (void)ocStaticFunc:(NSString *)log {
    NSLog(@"%@", log);
}

回到SwiftDemo.swift文件中,用swift调用OC的静态方法。

ViewController.ocStaticFunc("swift call oc static func")

Swift调用OC变参方法


在某些需求情景下,需要用到变参函数。简单举个例子:

+ (void) stringParams:(NSString*)params,...;

这种例子在系统函数中也可以见到。比如常用的NSString的一个方法:

- (instancetype)initWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);

OC的调用方法就不再重复了。这里说一下Swift怎么调用OC的变参方法。

首先,Swift不能直接调用OC的变参方法

如果必须要用到,则需要对函数进行简单修改。

拿上面刚说到的stringParams:方法举例。

需要把方法的写法改为:

+ (void) stringParams:(NSString*)params args:(va_list)args;

函数的具体实现:

+ (void) stringParams:(NSString *)params args:(va_list)args {

    va_list args_copy;

    __va_copy(args_copy,args);
    NSMutableString* format = [NSMutableString stringWithString:@""];
    while (va_arg(args, NSString*))
    {
        [format appendString:@"%@,"];
    }
    va_end(args);

    if(format.length>0)
        [format deleteCharactersInRange:NSMakeRange(format.length-1,1)];

    NSString* newFormat = [NSString stringWithFormat:@"%@",format];
    NSString * result = [[NSString alloc]initWithFormat:newFormat arguments:args_copy];
    va_end(args_copy);
    NSLog(@"%@", result);
}

在Swift中的调用方式:

let args: [CVarArgType] = ["i'm", " showhilllee"]
    withVaList(args) {
        (pointer: CVaListPointer) in
        return ViewController.stringParams("%@,%@", args:pointer)
    }

当然,还有其他方式来实现。可以尝试找一下方法。

结语


本文Demo可以在【这里】下载到

—End—

iOS面试 swift篇

阅读数 9

没有更多推荐了,返回首页