The application has a UITable View which loads dynamic images into cells. Images are downloaded while scrolling and they are converted into UIImages. Those UIImages will be set to the ImageView with help of KingFisher. Simple Cache mechanism has been already implemented but images are flash on scroll until the exact image loads. Code is mentioned below.
Table View Code
extension EmployeeListViewController:UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: EmployeeTableViewCell.self), for: indexPath) as! EmployeeTableViewCell
cell.onBindCell(management: (employeePresenter?.getManagementItem(position: indexPath.row))!)
cell.actionCallBack = self
let empIdNumber = NSString(string: (directoryPresenter!.getManagementItem(position: indexPath.row).agmid))
if let cachedImage = self.cache.object(forKey: empIdNumber) {
cell.profileImage.kf.base.image = cachedImage
} else {
directoryPresenter?.getProfileImage(id: empIdNumber as String) { image in
cell.profileImage.kf.base.image = image
self.cache.setObject(image!, forKey: empIdNumber)
}
}
return cell
}
}
Data Binding inside the Custom cell
I made the image data nil before reuse
override func prepareForReuse() {
profileImage.kf.base.image = nil
}
And set respective data inside onBind() data method.
func onBindCell(management: Management) {
name.text = management.getEmployeeDisplayName()
// Place Holder
profileImage.kf.base.image = UIImage(named: management.details.gender == "M" ? "placeholder_profile_male" : "placeholder_profile_female")
}
But Still, images blink when scrolling down the view for the first time. After the exact image is loaded it won't blick. How to sort the initial blinking issue on first scroll?
CodePudding user response:
What about still using KingFisher but telling it how to interpret/process the downloaded data?
Let's create our own ImageProcessor
:
struct CustomBase64Processor: ImageProcessor {
var identifier: String = "com.larme.customBase64Processor"
var encoding: String.Encoding = .utf8
func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
print("CustomBase64Processor Processing: \(item)")
switch item {
case .image(let image):
return image
case .data(let data):
// Strip the Base 64 data
if let utf8String = String(data: data, encoding: encoding) {
//Remove Data URI if needed
let base64String = utf8String.replacingOccurrences(of: "data:image\\/.*?;base64,",
with: "",
options: .regularExpression)
// Convert into a Data the Base64 Encoded String
if let cleanedData = Data(base64Encoded: base64String.trimmingCharacters(in: .whitespacesAndNewlines)) {
return KFCrossPlatformImage(data: cleanedData)
} else {
// Just an attempt here, but in fact it could be a gif, and that's not supported.
// Let's rely on KFCrossPlatformImage initilization
return KFCrossPlatformImage(data: Data(base64String.utf8))
}
} else {
//Default image data aren't UTF8 Convertible, and are "ready to process"
return KFCrossPlatformImage(data: data)
}
}
}
}
I was wondering if you had Data URI (since it made me think of related question), ie the content is data:image/png;base64,theBase64Data
, so I added a removal of it if needed.
In use, it's like that:
imageView.kf.setImage(with: url,
placeholder: nil,
options: [.processor(CustomBase64Processor())]) { result in
print("KingFisher callback: \(result)")
switch result {
case .success(let imageresult):
print("Success: \(imageresult)")
case .failure(let error):
print("Error: \(error)")
}
}
Be careful, since I made a processor, we should get a data
to interpret. So if you want to use other processing (like resizing, etc.) process the base 64 before to have a real working image first.
It's not fully tested, but I guess it could be a good start.
CodePudding user response:
I think you should use a library to load images from url