Trouble with UITableViewCell for MoPub Native Ad - ios

I integrated MoPub advertising for my iOS app to run some native ads in my UITableViewController (actually, it's a PFQueryTableViewController because I'm using Parse to load data into the tableView).
Everything is running fine - the console shows that ads are being loaded successfully, and I can see the extra cell in my tableView where the ad should be - the problem is that none of the content for the ad is showing up; I only see a blank cell.
The problem doesn't seem to be from MoPub. I think I'm setting up my cell incorrectly because I can't get ANYTHING to show up there.
I have tried 2 things.
Setting up the cell using storyboard. I added a new cell to my UITableViewController and created a new class for it, NativeAdCell. I designed IBOutlets and connected them to the class file.
The content is loaded through a MoPub function like so:
func layoutAdAssets(adObject: MPNativeAd!) {
adObject.loadIconIntoImageView(iconImageView)
adObject.loadTitleIntoLabel(titleLabel)
adObject.loadCallToActionTextIntoButton(callToActionButton)
adObject.loadImageIntoImageView(mainImageView)
adObject.loadTextIntoLabel(mainTextLabel)
}
The app crashes at the first line with console output (lldb).
Adding the outlets programmatically. In the NativeAdCell file I add outlets like so:
var mainTextLabel = UILabel()
var titleLabel = UILabel()
var iconImageView = UIImageView()
var mainImageView = UIImageView()
var callToActionButton = UIButton()
And later setting their frames.
The content is loaded with the same MoPub function. Now there is no crash, but the ad cell shows up completely blank with no content. Even if I manually set mainTextLabel.text = "Please show up" nothing will show up.
The crash when I try to load the IBOutlets makes me think something is wrong with the way I'm linking up the NativeAdCell to the tableView, but it seems like the MoPub SDK should handle this.
Can anybody spot the problem based on this info?

I achieved this without IBOutlets as follows, it's not well documented so I figured this might help someone out who is looking to use the MoPub SDK with custom cells for native ads
//
// AdTableViewCell.swift
// Trending-News
//
// Created by Conor Griffin on 22/07/2015.
// Copyright (c) 2015 Conor Griffin. All rights reserved.
//
import UIKit
import MoPub
class AdTableViewCell: UITableViewCell, MPNativeAdRendering {
var iconImageView: UIImageView! = UIImageView()
var titleLabel: UILabel! = UILabel()
var mainTextLabel: UILabel! = UILabel()
var advertIndicator: CGSponsoredLinkLabel! = CGSponsoredLinkLabel()
var adCorner: CGCornerHighlight! = CGCornerHighlight()
static func sizeWithMaximumWidth(maximumWidth: CGFloat) -> CGSize {
return CGSize(width: maximumWidth, height: 100)
}
override func layoutSubviews() {
super.layoutSubviews()
let width = CGRectGetWidth(frame)
let cellFrame = CGRect(x: 0, y: 0, width: width, height: 100)
iconImageView.layer.borderColor = UIColor.grayColor().CGColor
iconImageView.layer.borderWidth = 1
iconImageView.frame = CGRectMake(10, 10, 80, 80)
contentView.addSubview(iconImageView)
titleLabel.frame = CGRectMake(100, 10, self.frame.width - 110, 25)
contentView.addSubview(titleLabel)
mainTextLabel.frame = CGRectMake(100, 35, self.frame.width - 110, self.frame.height - 65)
contentView.addSubview(mainTextLabel)
mainTextLabel.numberOfLines = 3
mainTextLabel.font = UIFont.systemFontOfSize(11.0)
advertIndicator.frame = CGRectMake(100, self.frame.height - 30, self.frame.width - 110, self.frame.height - 80)
contentView.addSubview(advertIndicator)
advertIndicator.font = UIFont.systemFontOfSize(10.0)
advertIndicator.text = "Advertisement"
advertIndicator.textColor = UIColor.darkGrayColor()
advertIndicator.backgroundColor = UIColor(red: 252/255.0, green: 246/255.0, blue: 220/255.0, alpha: 1.0)
advertIndicator.clipsToBounds = true
advertIndicator.layer.masksToBounds = true
advertIndicator.layer.cornerRadius = 3
}
func layoutAdAssets(adObject: MPNativeAd!) {
adObject.loadTitleIntoLabel(titleLabel)
adObject.loadTextIntoLabel(mainTextLabel)
adObject.loadIconIntoImageView(iconImageView)
}
}

It's quite magical, really, that I forgot to add the subviews to the contentView of the NativeAdCell. self.contentView.addSubview(mainTextLabel) etc solves #2.
Not sure how to get this to work with IBOutlets still. It would be a lot easier that way (removes need for programmatic constraints).

Related

Set a special string to the UILabel, but the part of string is duplicated and be strange

My user report a bug that the texts is strange and he did not taped that.
So I get the texts and create a simple project, only create a label and set the texts to it.
The texts is here:
【Does this sound natural?】\n \"Who's that?\" \"That's Tom when he was a kid.\" \"Do you have a same picture of Mary?
If I do not limit the number of label's line, there is no issue, but when set the number of line to 3, the text "That's Tom when occurred two times! And texts is became strange.
All code is here
class ViewController: UIViewController {
lazy var label: UILabel = {
let label = UILabel(frame: CGRect(x: 50, y: 100, width: 220, height: 100))
label.numberOfLines = 3
label.font = UIFont.systemFont(ofSize: 14)
self.view.addSubview(label)
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = .lightGray
self.label.text = "【Does this sound natural?】\n \"Who's that?\" \"That's Tom when he was a kid.\" \"Do you have a same picture of Mary?"
}
}
According to the discussion here it is a bug occurring after iOS 15.4.
There is a workaround mentioned in the above thread.
I also faced the same issue and I changed the UILabel to a UITextView with the two options
label.textContainer.maximumNumberOfLines = 3
label.textContainer.lineBreakMode = .byTruncatingTail
Check if either of workarounds will work in your case.

"removeFromSuperview" NEVER work on UIApplication?

How to remove subviews?
I am trying to integrate GIF by creating UIView and UIImageView programmatically.
It works fine to show GIF but when the function of hiding if is called, there is no response.
Here are the codes of both functions.
class CustomLoader: UIView {
static let instance = CustomLoader()
var viewColor: UIColor = .black
var setAlpha: CGFloat = 0.5
var gifName: String = ""
lazy var transparentView: UIView = {
let transparentView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
transparentView.backgroundColor = viewColor.withAlphaComponent(setAlpha)
transparentView.isUserInteractionEnabled = false
return transparentView
}()
lazy var gifImage: UIImageView = {
var gifImage = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 60))
gifImage.contentMode = .scaleAspectFit
gifImage.center = transparentView.center
gifImage.isUserInteractionEnabled = false
gifImage.loadGif(name: gifName)
return gifImage
}()
func showLoaderView() {
self.addSubview(self.transparentView)
self.transparentView.addSubview(self.gifImage)
self.transparentView.bringSubview(toFront: self.gifImage)
UIApplication.shared.keyWindow?.addSubview(transparentView)
}
func hideLoaderView() {
self.transparentView.removeFromSuperview()
}
}
A couple of thoughts:
I’d suggest you add a breakpoint or a logging statement in hideLoaderView and make sure you’re getting to that line.
You should make the init method to this class private to make sure you’re not calling hideLoaderView on some separate instance. When dealing with singletons, you want to make sure you can’t accidentally create another instance.
But I tested your code, and it works fine. Your problem probably rests with where and how you call this (and making init private, you might find where you might be using it inappropriately).
In the comments below, you said:
I simply call the function "CustomLoader().hideLoaderView()" Both are being called technically. What do you mean by "where I using it inappropriately?"
That is the root of the problem.
The CustomLoader() of CustomLoader().hideLoaderView() will create a new instance of CustomLoader with its own transparencyView, etc., which is precisely what the problem is. You’re not hiding the old view that was presented earlier, but trying to hide another one that you just created and was never displayed.
If you instead use that static, e.g. CustomLoader.instance.showLoaderView() and CustomLoader.instance.hideLoaderView(), then the problem will go away. Then you will be hiding the same view that your previously showed.
By the way, a few other unrelated observations:
If this is a singleton or shared instance, the convention would be to call that static property shared, not instance.
By the way, you aren’t using this CustomLoader as a UIView, so I’d not make it a UIView subclass. Don’t make it a subclass of anything.
You would obviously eliminate that self.addSubview(transparentView) line, too.
The bringSubview(toFront:) call is unnecessary.
You should avoid referencing UIScreen.main.bounds. You don’t know if your app might be in multitasking mode (maybe this isn’t an issue right now, but it’s the sort of unnecessary assumption that will cause problems at some later date). Just refer to the bounds of the UIWindow to which you’re adding this. You should also update this frame when you show this view, not when you create it (in case you changed orientation in the intervening time, or whatever).
By the way, using keyWindow is discouraged in iOS 13 and later, so you might eventually want to remove that, too.
When adding the gifImage (which I’d suggest renaming to gifImageView because it’s an image view, not an image), you should not reference the center of its superview. That’s the coordinate of the transparent view in its super view’s coordinate system, which could be completely different than the transparent view’s own coordinate system. In this case, it just happens to work, but it suggests a fundamental misunderstanding of view coordinate systems. Reference the bounds of the transparentView, not its center.
If you’re going to expose viewColor and setAlpha, you should pull the setting of the transparentView’s color out of the lazy initializer and into showLoaderView, at the very least. Right now, if you show the loader once, and then change the color, and try to show it again, you won’t see the new color.
The same issue applies with the gif image. So, I’d move that to the didSet observer.
Thus, pulling this all together:
class CustomLoader{
static let shared = CustomLoader()
private init() { }
var dimmingColor: UIColor = .black
var dimmingAlpha: CGFloat = 0.5
var gifName: String = "" { didSet { gifImage.loadGif(name: gifName) } }
lazy var transparentView: UIView = {
let transparentView = UIView()
transparentView.isUserInteractionEnabled = false
return transparentView
}()
lazy var gifImageView: UIImageView = {
var gifImage = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 60))
gifImage.contentMode = .scaleAspectFit
gifImage.isUserInteractionEnabled = false
return gifImage
}()
func showLoaderView() {
guard let window = UIApplication.shared.keyWindow else { return }
transparentView.frame = window.bounds
transparentView.backgroundColor = dimmingColor.withAlphaComponent(dimmingAlpha)
gifImageView.center = CGPoint(x: transparentView.bounds.midX, y: transparentView.bounds.midY)
transparentView.addSubview(gifImageView)
window.addSubview(transparentView)
}
func hideLoaderView() {
transparentView.removeFromSuperview()
}
}
Why you are using transparentView while you are have a CustomLoader instance view
Try to use this
class CustomLoader: UIView {
static let instance = CustomLoader()
var viewColor: UIColor = .black
var setAlpha: CGFloat = 0.5
var gifName: String = ""
init() {
super.init(frame: UIScreen.main.bounds)
backgroundColor = viewColor.withAlphaComponent(setAlpha)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var gifImage: UIImageView = {
var gifImage = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 60))
gifImage.backgroundColor = .red
gifImage.contentMode = .scaleAspectFit
gifImage.center = center
gifImage.isUserInteractionEnabled = false
gifImage.loadGif(name: gifName)
return gifImage
}()
func showLoaderView() {
addSubview(self.gifImage)
UIApplication.shared.keyWindow?.addSubview(self)
}
func hideLoaderView() {
removeFromSuperview()
}
}

Nothing is showing when using BCMeshTransformView

I wanted to use BCMeshTransformView library into my swift project. I've created an empty swift project and added the library via cocoa pods.
Here's my ViewController class:
import UIKit
import BCMeshTransformView
class ViewController: UIViewController {
var transformView:BCMeshTransformView!
var imageView:UIImageView!
var transform:BCMutableMeshTransform!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
transformView = BCMeshTransformView(frame: self.view.bounds)
transformView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
imageView = UIImageView(image: UIImage(named: "picture.jpg")!)
imageView.center = CGPoint(x: transformView.contentView.bounds.midX, y: transformView.contentView.bounds.midY)
transformView.contentView.addSubview(imageView)
transformView.diffuseLightFactor = 0.0
transform = BCMutableMeshTransform.identityMeshTransform(withNumberOfRows: 20, numberOfColumns: 20)
transform.mapVertices { (vertex, vertexIndex) -> BCMeshVertex in
return BCMeshVertex(from: vertex.from, to: vertex.to)
}
transformView.meshTransform = transform
self.view.addSubview(transformView)
}
}
When I'm running the app nothing is showing. It's entirely white.
Removing this code:
transform = BCMutableMeshTransform.identityMeshTransform(withNumberOfRows: 20, numberOfColumns: 20)
transform.mapVertices { (vertex, vertexIndex) -> BCMeshVertex in
return BCMeshVertex(from: vertex.from, to: vertex.to)
}
transformView.meshTransform = transform
doesn't change anything.
But when in xcode I'm switching to "Show UI hierarchy" I can see an image:
Here's a whole sample project:
http://www116.zippyshare.com/v/IUTXbKJg/file.html
Why I cannot see anything? I tried making an example as simple as possible.
Looks like that was a problem with that library codun't find shader files. I had to copy BCMeshShader.fsh and BCMeshShader.vsh to my project.

Difficulty loading Image in Swift with Kingfisher

I have a strange problem. I am trying to use Kingfisher in order to load and an cache an Image from Firebase in my app. The problem is that kKingfisher does not download the image. I am using a Placeholder Image that is locally stored and the scroll view displays that Image. If I remove the placeholder part from the command, the app crashes. So I know the Kingfisher function works by at least placing the placeholder Image into the UIImageView but not the image from the URL. Here is the code:
Can you point me to the right direction?
import UIKit
import Kingfisher
class Backprogramme: UIViewController {
override var prefersStatusBarHidden: Bool {
return true
}
#IBOutlet var BackPScroll: UIScrollView!
var imageArray = [UIImage]()
var folie1Image = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
let folie1URL = URL(string: "https://firebasestorage.googleapis.com/v0/b/backmaster-cdb60.appspot.com/o/Folie1.PNG?alt=media&token=efcb8e93-b817-41f3-a96f-946fd47cf468")!
folie1Image.kf.setImage(with: folie1URL, placeholder: #imageLiteral(resourceName: "first"))
imageArray = [folie1Image.image!]
for i in 0..<imageArray.count {
let imageView = UIImageView()
imageView.image = imageArray[i]
let xPosition = self.view.frame.width * CGFloat(i)
imageView.frame = CGRect(x: xPosition, y: 0, width: self.BackPScroll.frame.width, height: self.BackPScroll.frame.height)
BackPScroll.contentSize.width = BackPScroll.frame.width * CGFloat(i+1)
BackPScroll.addSubview(imageView)
}
// Do any additional setup after loading the view.
}
}
I had the same issue , discovered I had this in the log "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection" .
I fixed it by adding NSAppTransportSecurity as a Dictionary in the info.plist and then I added Allow Arbitrary Loads boolean with YES as a value . It worked instantly.

Create UIContainerView programmatically

I've just started to code my app in Swift 2 and avoiding the use of XIBs and storyboards.
However, I am unable to replicate the following feature. It's exactly what I wanted.
I've tried creating a UIView to perform the following using .backgroundColor and it works, however, I am unable to link it to my UIViewControllers. Just wondering how is it done? How do I link my UIView to my UIViewController?
Codes:
let subFrame : CGRect = CGRectMake(0,screenHeight*1/2.75,screenWidth,screenHeight)
var loginView = SignUpViewController()
let signUpView: UIView = UIView(frame: subFrame)
signUpView.backgroundColor = UIColor.redColor()
//Controls what each segment does
switch segmentView.indexOfSelectedSegment {
case 0:
self.view.addSubview(signUpView)
case 1:
self.view.addSubview(loginView)
default:
break;
}
I'm not even sure if .view.addSubview(xxx) overwrites/replaces the original subview if it is not this way. Is this the right way to do it?
Do not just start coding an app if you are not familiar with simple things of the OOP (Object-Oriented-Programming) language like Swift. This is not the way how to learn a programming language. Sure you could learn while experimenting but it is better to understand the book first before starting with more complex stuff. Read a few more pages of the Swift book from Apple. Most classes for iOS development are still Objective-C wrapped classes (reference type because the top superClass is probably NSObject; keep this in mind).
Here is the code example you wanted:
class ViewController: UIViewController {
let firstView = UIView()
let secondView = UIView()
let segmentedControlView = UISegmentedControl(items: ["firstView", "secondView"])
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor() // we need this for the playground
/* setup your view here */
/* add your sigment logic somewhere */
self.view.addSubview(self.segmentedControlView)
self.view.addSubview(self.firstView)
self.view.addSubview(self.secondView)
self.segmentedControlView.frame = CGRect(x: 0, y: 20, width: self.view.frame.width, height: 44)
self.segmentedControlView.selectedSegmentIndex = 0 // enable the first segment
self.segmentedControlView.addTarget(self, action: "segmentIndexChanged:", forControlEvents: UIControlEvents.ValueChanged)
/* add your own frame calculation here */
/* I prefer AutoLayout, but for the example static frames will be fine */
self.firstView.frame.origin = CGPoint(x: 0, y: self.segmentedControlView.frame.origin.y + self.segmentedControlView.frame.height)
self.firstView.frame.size = CGSize(width: self.view.frame.width, height: self.view.frame.height - self.segmentedControlView.frame.origin.y)
// to prevent same code, we just copy the same frame from the firstView
// both will sit in the same place
self.secondView.frame = self.firstView.frame
/* lets add some colors so we'll see our views */
self.firstView.backgroundColor = UIColor.blueColor()
self.secondView.backgroundColor = UIColor.redColor()
self.secondView.hidden = true // when intializer the secondView is not visible
}
func segmentIndexChanged(sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
self.firstView.hidden = false
self.secondView.hidden = true
case 1:
self.firstView.hidden = true
self.secondView.hidden = false
default:
break;
}
}
}
If you do not understand a function, should should look up its definition in the developer docs. (Like: addSubview)

Resources