Closed Nico3652 closed 4 weeks ago
hey @Nico3652 thanks for flagging this, sorry for the late reply. I'm using the latest Xcode from the App Store (14.3) and was unable to reproduce based on the code you shared, though I had to add self.addChild(gridController)
in order for it to work. Could you try just presenting the GiphyViewController
and let me know if that leads to a crash for you as well?
@cgmaier thanks for reply, I'm also using this version of Xcode.
I can confirm that this is not happening presenting the GiphyViewController
.
I can also confirm it never happen on the first opening : I have to present 3-5x my modal quickly to make it crash.
In order to add more context to my situation, I'm not building an iOS app in full swift code but a Flutter app mixing dart & swift. I suppose you may be not an expert in flutter, but concepts are equals.
The main view I'm using is just a wrapper to insert the gridController :
mainView!.addSubview(gridController!.view)
It worked perfectly during months.
I cannot use self.addChild(gridController)
because the rootVC is in flutter. I'm only retrieving the grid view and add it in my view.
Do you think the problem could be linked to this ?
So I have done many tests and here is my workaround :
I have removed gridController!.update()
from my initController
and create another func
to update the grid with some delay (1s for now).
This workaround is working great for now until im able to understand this behavior and fix it.
hey @Nico3652 glad you found a solution. can you try creating a new GiphyGridController
every time? I think the issue may be related to using the same instance.
https://github.com/Giphy/giphy-ios-sdk/blob/main/Docs.md#giphygridcontroller-presentation
@cgmaier I followed the entire documentation,
I'm setting to nil
the instance every time the page is closed and recreate it inside the init
func and only if it's == to nil to avoid duplicate instance
are you also removing it from the view hierarchy?
@cgmaier indeed I'm removing it like this :
// Called when the modal is dismissed
func dismiss(completion: ((Bool?)->Void?)) {
if(gridController != nil) {
gridController!.view.removeFromSuperview()
}
gridController = nil
querySearch = nil
completion(true)
}
However I'm not an expert in Swift and iOS behavior, am I doing it wrong ?
Here is the full wrapper class I've created for handling the grid :
import Foundation
import GiphyUISDK
class GiphyController: NSObject {
//var giphy: GiphyViewController?
var gridController: GiphyGridController?
var mainView: UIView?
var content: GPHContent?
var querySearch: String?
var currentType: String?
var channel: FlutterMethodChannel?
var rootController: UIViewController?
// Called inside AppDelegate
func initVC(_ ch: FlutterMethodChannel, _ rootVC: UIViewController) {
mainView = UIView()
channel = ch
//setCacheSize(size: 100)
// TEST WITH VIEW CONTROLLER
//
// rootController = rootVC
// giphy = GiphyViewController()
// giphy!.mediaTypeConfig = [.recents, .stickers, .emoji, .text, .gifs]
// giphy!.theme = GPHTheme(type: Constants.onDarkMode ? .darkBlur : .lightBlur)
// giphy!.stickerColumnCount = GPHStickerColumnCount.three
// giphy!.shouldLocalizeSearch = true
// rootController?.present(giphy!, animated: true, completion: nil)
// return
}
// Called only once when the modal show up
func initController(completion: ((Bool?) -> Void?)) {
if(gridController == nil) {
gridController = GiphyGridController()
gridController!.delegate = self
// space between cells
gridController!.cellPadding = 4.0
// the scroll direction of the grid
gridController!.direction = .vertical
// the number of "tracks" is the span count. it represents num columns for vertical grids & num rows for horizontal grids
gridController!.numberOfTracks = 3
// hide the checkered background for stickers if you'd like (true by default)
//gridController!.showCheckeredBackground = false
gridController!.view.backgroundColor = .clear
gridController!.theme = GiphyGridTheme()
// by default, the waterfall layout sizes cells according to the aspect ratio of the media
// the fixedSizeCells setting makes it so each cell is square
// this setting only applies to Stickers (not GIFs)
gridController!.fixedSizeCells = true
mainView!.addSubview(gridController!.view)
gridController!.view.translatesAutoresizingMaskIntoConstraints = false
gridController!.view.leftAnchor.constraint(equalTo: mainView!.safeLeftAnchor).isActive = true
gridController!.view.rightAnchor.constraint(equalTo: mainView!.safeRightAnchor).isActive = true
gridController!.view.topAnchor.constraint(equalTo: mainView!.safeTopAnchor).isActive = true
gridController!.view.bottomAnchor.constraint(equalTo: mainView!.safeBottomAnchor).isActive = true
completion(true)
}
else {
completion(false)
}
}
// Called when the modal is dismissed
func dismiss(completion: ((Bool?)->Void?)) {
if(gridController != nil) {
gridController!.view.removeFromSuperview()
}
gridController = nil
querySearch = nil
completion(true)
}
func getMedia(id: String, completion: ((String?) -> Void)? = nil) {
GiphyCore.shared.gifByID(id) { (response, error) in
if let media = response?.data {
DispatchQueue.main.sync { [weak self] in
let url = media.url(rendition: .fixedWidth, fileType: .gif)
completion?(url)
}
}
else {
completion?(nil)
}
}
}
func downloadMedia(id: String, completion: ((Data?) -> Void)? = nil) {
getMedia(id: id, completion: { url in
if(url != nil) {
GPHCache.shared.downloadAssetData(url!) { (data, error) in
completion?(data)
}
}
})
}
func search(query: String, type: String, completion: ((Bool?) ->Void?)) {
if(gridController != nil) {
querySearch = query
let type = getTypeWithString(type: type)
// TODO : change the localization
gridController!.content = GPHContent.search(withQuery: query, mediaType: type, language: .french, includeDynamicResults: true)
gridController!.update()
completion(true)
}
else {
completion(false)
}
}
func clearSearch(completion: ((Bool?)->Void?)) {
querySearch = nil
if(currentType != nil) {
update(type: currentType!, completion: { success in
completion(success)
})
}
else {
completion(false)
}
}
// Called to update the grid content according the current type
func update(type: String, completion: ((Bool?)->Void?)) {
if(gridController == nil) {
completion(false)
return
}
// Only affected here in order to reset the current TAB in grid after clearSearch()
currentType = type
// If there is already a keyword in search we just update the content according the query
// Otherwise moving the content the trend according type
//
// If the type is recent or emoji there is no query to make for because this is fixed result
if(querySearch != nil && type != "recently" && type != "emoji") {
search(query: querySearch!, type: type,completion: { success in
completion(success)
})
return
}
// Update the grid gif according the type
var content = GPHContent.recents
switch type {
case "recently":
// initialize with recents so don't need to re affect
break
case "stickers":
content = GPHContent.trending(mediaType: .sticker)
break
case "emoji":
content = GPHContent.emoji
break
case "text":
content = GPHContent.trending(mediaType: .text)
break
case "gif":
content = GPHContent.trending(mediaType: .gif)
break
default:
break
}
gridController!.content = content
gridController!.update()
completion(true)
}
func getRecentCount(completion: ((Int?)->Void?)) {
let count = GPHRecents.count
completion(count)
}
func clearRecent(completion: ((Bool?) -> Void)) {
GPHRecents.clear()
completion(true)
}
func getTypeWithString(type: String) -> GPHMediaType {
// The search is not possible when this is recent or emoji because this is fixed list
// for the user
switch type {
case "recently":
return .sticker
case "text":
return .text
case "stickers":
return .sticker
case "emoji":
return .sticker
case "gif":
return .gif
default:
return .sticker
}
}
func setCacheSize(size: Int) {
GPHCache.shared.cache.diskCapacity = size
GPHCache.shared.cache.memoryCapacity = size
}
func clearCache() {
GPHCache.shared.clear()
}
}
extension GiphyController: GPHGridDelegate {
func contentDidUpdate(resultCount: Int, error: Error?) {
}
func didSelectMoreByYou(query: String) {
}
func didScroll(offset: CGFloat) {
channel?.invokeMethod("onScroll", arguments: offset)
}
func contentDidUpdate(resultCount: Int) {
}
func didSelectMedia(media: GPHMedia, cell: UICollectionViewCell) {
var args = [String: Any]()
args["id"] = media.id
args["ratio"] = media.aspectRatio
channel?.invokeMethod("onMediaPicked", arguments: args)
}
}
class GiphyGridTheme: GPHTheme {
override var backgroundColorForLoadingCells: UIColor {
return .clear
}
}
This issue might be a duplicate of #257
During 6 months of testing I had no error / crashes using this SDK but recently (maybe with new Xcode version) I'm getting a crash when I'm initializing the main grid for recents with exactly the same code than previous months :
And then I'm getting this error :
Thanks in advance