I have a project that I have built where I am trying to include the sinch framework for making SMS verification. I added Sinch to the project VIA cocoapods, and also by manually adding the folder/framework to my xcode file system.
The problem i'm having right now is that my version of the CountrySelectionViewController.swift cannot access the SinRegionInfo protocol defined inside of the Sinch framework... i'm not sure what is going wrong. An example of the code/error inside CountrySelectionViewController.swift is here:
var entries: Array<SINRegionInfo> = []; ---> Use of undeclared type 'SinRegionInfo'
The strange part is that everything seems to be the same in my project as it is in the sample project, but in the sample project, there is no problem accessing the protocol.
CountrySelectionViewController.swift
import UIKit
import SinchVerification
class CountrySelectionViewController : UITableViewController {
var isoCountryCode: String?
var onCompletion: ((String) -> Void)?
var entries: Array<SINRegionInfo> = [];
override func viewDidLoad() {
super.viewDidLoad();
let regionList = PhoneNumberUtil().regionList(forLocale: Locale.current);
entries = regionList.entries.sorted(by: { (a: SINRegionInfo, b: SINRegionInfo) -> Bool in
return a.countryDisplayName < b.countryDisplayName;
})
}
override func viewWillAppear(_ animated: Bool) {
let row = entries.index { (region: SINRegionInfo) -> Bool in
return region.isoCountryCode == isoCountryCode;
}
if row != nil {
tableView.selectRow(at: IndexPath.init(row: Int(row!), section: 0), animated: animated, scrollPosition: .middle);
}
}
Related
I am working on a webrtc screensharing app. Therefore I am utilizing the objective-c webrtc framework.
Now I have problems on how to pass in the RTCVideoEncoderSettings (http://cocoadocs.org/docsets/GoogleWebRTC/1.1.20266/Classes/RTCVideoEncoderSettings.html)
into an encoder (VP9). This is what I currently have:
public class CustomVideoEncoderFactory : NSObject, RTCVideoEncoderFactory {
var encoder: RTCVideoEncoder?
var preferredCodec: RTCVideoCodecInfo = RTCVideoCodecInfo(name: "VP9")
public func createEncoder(_ info: RTCVideoCodecInfo) -> RTCVideoEncoder? {
let vp9Encoder = RTCVideoEncoderVP9.vp9Encoder()!
// How to pass the RTCVideoEncoderSettings into this encoder???
return vp9Encoder
}
public func supportedCodecs() -> [RTCVideoCodecInfo] {
return [RTCVideoCodecInfo(name: "VP9")]
}
}
There is a method called startEncodeWithSettings (http://cocoadocs.org/docsets/GoogleWebRTC/1.1.20266/Protocols/RTCVideoEncoder.html)
but I am unsure how to integrate this with my current code. I tried to subclass (public class CustomVideoEncoder: NSObject, RTCVideoEncoder { ... }) which did not work.
Thank you for your help!
Ok, I found a solution. It turns out that for VP9 and VP8 there are the objective-c wrappings missing. VP9 and Vp8 are directly link to the native implementation!
Therefore it is ONLY possible to subclass if you are using h264.
For changing the settings on VP9 and VP8 it is necessary to modify the settings inside the c++ code!
Example of a custom Encoder Factory:
public class CustomVideoEncoderFactory : NSObject, RTCVideoEncoderFactory {
public func createEncoder(_ info: RTCVideoCodecInfo) -> RTCVideoEncoder? {
let encoder = super.createEncoder(info) // will create the h264 encoder
let customEncoder = CustomVideoEncoder()
self.encoder = customEncoder
return encoder
}
public func supportedCodecs() -> [RTCVideoCodecInfo] {
return [RTCVideoCodecInfo(name: kRTCVideoCodecH264Name)] }}
Example of a custom Encoder:
public class CustomVideoEncoder: NSObject, RTCVideoEncoder {
public var encoder: RTCVideoEncoder? // ONLY WORKS WITH h264
public func setCallback(_ callback: #escaping RTCVideoEncoderCallback) {
return encoder!.setCallback(callback)
}
public func startEncode(with settings: RTCVideoEncoderSettings, numberOfCores: Int32) -> Int {
// Change settings here !
let res = encoder!.startEncode(with: settings, numberOfCores: numberOfCores)
}
public func release() -> Int {
return encoder!.release()
}
public func encode(_ frame: RTCVideoFrame, codecSpecificInfo info: RTCCodecSpecificInfo?, frameTypes: [NSNumber]) -> Int {
return encoder!.encode(frame, codecSpecificInfo: info, frameTypes: frameTypes)
}
public func setBitrate(_ bitrateKbit: UInt32, framerate: UInt32) -> Int32 {
return encoder!.setBitrate(bitrateKbit, framerate: framerate)
}
public func implementationName() -> String {
return encoder!.implementationName()
}
public func scalingSettings() -> RTCVideoEncoderQpThresholds? {
return encoder!.scalingSettings()
}}
startEncodeWithSettings is an instance method, so you use it with an instance of it's type - did you try [encoder startEncodeWithSettings:param1 numberOfCores:param2]?
I am trying to implement a UICollectionViewDiffableDataSource for my collectionView. My code compiles fine, however I keep running into this error the first time I apply a snapshot to it, with the following error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: self.supplementaryViewProvider || (self.supplementaryReuseIdentifierProvider && self.supplementaryViewConfigurationHandler)'
Here is my code:
var groups: [Group] = [Group]()
var dataSource: UICollectionViewDiffableDataSource<Section, Group>!
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
self.searchBar.delegate = self
self.groups = DummyData.groups
setupDataSource()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
performSearch(searchQuery: nil)
}
// MARK: - Helper Functions
func performSearch(searchQuery: String?) {
let filteredGroups: [Group]
if let searchQuery = searchQuery, !searchQuery.isEmpty {
filteredGroups = groups.filter { $0.contains(query: searchQuery) }
} else {
filteredGroups = groups
}
var snapshot = NSDiffableDataSourceSnapshot<Section, Group>()
snapshot.appendSections([.main])
snapshot.appendItems(filteredGroups, toSection: .main)
dataSource.apply(snapshot, animatingDifferences: true, completion: nil)
}
func setupDataSource() {
dataSource = UICollectionViewDiffableDataSource <Section, Group>(collectionView: collectionView) { (collectionView: UICollectionView, indexPath: IndexPath, group: Group) -> UICollectionViewCell? in
guard let cell = self.collectionView.dequeueReusableCell(
withReuseIdentifier: String(describing: MyGroupsCollectionViewCell.self), for: indexPath) as? MyGroupsCollectionViewCell else {
fatalError("Cannot create new cell") }
cell.configure(withGroup: group)
return cell
}
}
If needed, I can post the full call stack.
Found the answer. I was using the storyboard to create my collectionView and accidentally had the attribute for Section Header set to true. Because of this, the collectionView needed to pull the view for the section header for somewhere, but I never told it where, hence the
parameter not satisfying: self.supplementaryViewProvider || (self.supplementaryReuseIdentifierProvider && self.supplementaryViewConfigurationHandler)
Here's a good article I found on it for anyone in the future who runs into this issue:
https://medium.com/#jamesrochabrun/uicollectionviewdiffabledatasource-and-decodable-step-by-step-6b727dd2485
I'm testing with an iPhone 5 in Swift 2.0, Xcode 7.1 and iOS 9.1 with a good wifi connection.
I have followed this tutorial ( http://www.appcoda.com/google-sign-in-how-to/ ) and everything works fine on simulator but when I run this app on a real device using my iPhone 5 it opens the Google search App (with some registered accounts inside them) for handle sign in. It prompts the user to select an account. Once an account is selected, the google search app then asks the user if my app can access their information. Once a user clicks SIGN IN,
After, when come back on the app code don't enter on this function:
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
print(err)
}
else {
performSegueWithIdentifier("idSegueContent", sender: self)
}
}
My main ViewController() class is this:
import UIKit
class ViewController: UIViewController, GIDSignInDelegate, GIDSignInUIDelegate {
#IBOutlet weak var signInButton: GIDSignInButton!
var contentViewController: ContentViewController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().clientID = "MY_CLIENT_ID"
GIDSignIn.sharedInstance().scopes.append("https://www.googleapis.com/auth/plus.login")
GIDSignIn.sharedInstance().scopes.append("https://www.googleapis.com/auth/plus.me")
GIDSignIn.sharedInstance().signInSilently()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Google SignIn Delegate Methods
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
print(err)
}
else {
performSegueWithIdentifier("idSegueContent", sender: self)
}
}
func signIn(signIn: GIDSignIn!, didDisconnectWithUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
print(err)
}
contentViewController.dismissViewControllerAnimated(true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "idSegueContent" {
contentViewController = segue.destinationViewController as! ContentViewController
}
}
}
If the Google search app is not installed, then Safari opens in the app just fine and once signed in, the delegate callback methods work just as expected.
I had the same issue and finally got it working after restarting my phone. (After hours of tests, checks, and re-organizing code!) Hopefully this simple solution saves someone else from the trouble.
I have a huge background as c++ dev, but I'm still newbie in Swift/Objective-C zone. I'm trying to build a class hierarchy and I'm kind of stuck with this code:
protocol CADelegate : class {
func g()
}
class CA : NSObject {
init(i: Int) {}
func f() {
if let del = getDelegate() {
del.g()
} else {
println("delegate is null")
}
}
private func getDelegate() -> CADelegate? {
return nil
}
}
class CB : CA {
override init(i: Int) {
super.init(i:i)
}
var delegate: CADelegate!
private override func getDelegate() -> CADelegate? {
return delegate
}
}
class Client : CADelegate {
func g() {
println("CA delegate")
}
}
class ViewController : ... {
override func viewDidLoad() {
var cb = CB(i: 1)
var client = Client()
cb.delegate = client // the problem row!!!
cb.f()
}
}
On "the problem row" I got an runtime error EXC_BAD_ACCESS(code=1,address=...).
Can somebody help me figure this out? I know I'm doing something wrong, because I'm use to C++ idioms and programming style.
NOTE: also the same is true if the delegate property is weak, as it is in my original code.
Edit 1:
I'm using XCode6 Beta 7
Edit 2:
As it turns out it is not 100% reproducible. 3 out of 5 times it is working but for the other 2 times I've got the bad access exception. It looks like a race condition, but I'm not using any other tasks/threads. This is my main view controller and viewDidLoad should be called on view controller initialization.
Edit 3:
Even more strange - if I remove my constructors in CA and CB, and change the creation of CB without int parameter, the problem disappears! I'm sure now it looks like a bug :)
I canĀ“t get the object properties when retrieving an object from Parse Data Browser. This happened after I changed from "#NSManaged var friends" to "dynamic var friends". Even "name" show nil in User.logInWithUsernameInBackground block which is crazy because the login succeeds. The ACL for User is set to "public read".
User object:
class User : PFUser, PFSubclassing {
dynamic var friends:[User]!
dynamic var name:String!
override class func load() {
self.registerSubclass()
}
}
Retrieving the User along with the friends. println showing nil
var query = User.query()
query.includeKey("friends")
query.getObjectInBackgroundWithId(currentUser.objectId) {
(pfObject: PFObject!, error: NSError!) -> Void in
if pfObject != nil {
var user = pfObject as User
var friends = user.friends as [User]
println("friends: \(friends)") //nil
} else {
println(error)
}
}
Login. println showing nil
User.logInWithUsernameInBackground(USERNAME, password:PASSWORD) {
(user: PFUser!, error: NSError!) -> Void in
if user != nil {
println("Logged in with user: \(user.name)") //nil
} else {
println(error)
}
}
Looking a little deeper for you, it seems the hurdle is a misunderstanding of what the dynamic modifier in Swift does. Apparently, dynamic in Swift is used for Key-Value observing, not declaring a variable's accessors to be defined at runtime (what #dynamic does in Objective-C)
See this for a description of dynamic in Swift https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-XID_8
and this for the description of why #NSManaged works the way #dynamic does in Objective-C
https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WritingSwiftClassesWithObjective-CBehavior.html#//apple_ref/doc/uid/TP40014216-CH5-XID_66
With xCode 6.1.1 I was able to get this working without the bridging header but I did need to use #NSManaged. Here's how... Just:
import Parse
at the top of the calling module. For the class declaration .swift file dynamic didn't work so I needed to use #NSManaged for the variable types to get them to link to the Parse class variables successfully. Like this:
class PSCategory : PFObject, PFSubclassing {
override class func load() {
self.registerSubclass()
}
class func parseClassName() -> String! {
return "Category"
}
#NSManaged var Name: String
}
Then in my query all the names are dynamically linked:
var query = PSCategory.query() // PFQuery(className: "Category")
query.cachePolicy = kPFCachePolicyCacheElseNetwork // kPFCachePolicyNetworkElseCache
query.maxCacheAge = 60 * 60 * 24 // One day, in seconds.
query.findObjectsInBackgroundWithBlock {
(categories: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
for abstractCategory in categories {
let category = abstractCategory as PSCategory
NSLog("Category Name: %#", category.Name)
}
} else {
NSLog("Unable to retrieve categories from local cache or network")
}
}